Drop php74 (#120)
* PHPStan Level 6 * Drop PHP 7.4 support * Add PHPStan badge to readme * Code style cleanup
This commit is contained in:
parent
c59f4cd153
commit
7704ba918f
12 changed files with 72 additions and 120 deletions
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
@ -8,7 +8,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: [8.2, 8.1, 8.0, 7.4]
|
||||
php: [8.2, 8.1, 8.0]
|
||||
dependency-version: [prefer-lowest, prefer-stable]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# MathExecutor [![Tests](https://github.com/neonxp/MathExecutor/workflows/Tests/badge.svg)](https://github.com/neonxp/MathExecutor/actions?query=workflow%3ATests)
|
||||
# MathExecutor [![Tests](https://github.com/neonxp/MathExecutor/workflows/Tests/badge.svg)](https://github.com/neonxp/MathExecutor/actions?query=workflow%3ATests) ![](https://img.shields.io/badge/PHPStan-level%206-brightgreen.svg?style=flat)
|
||||
|
||||
# A simple and extensible math expressions calculator
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=9.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.8"
|
||||
"friendsofphp/php-cs-fixer": "^3.8",
|
||||
"phpstan/phpstan": "^1.9"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- ./
|
||||
excludes_analyse:
|
||||
- vendor/*
|
||||
- tests/*
|
||||
bootstrapFiles:
|
||||
- vendor/autoload.php
|
7
phpstan.neon.dist
Normal file
7
phpstan.neon.dist
Normal file
|
@ -0,0 +1,7 @@
|
|||
parameters:
|
||||
level: 6
|
||||
errorFormat: raw
|
||||
editorUrl: '%%file%% %%line%% %%column%%: %%error%%'
|
||||
paths:
|
||||
- src
|
||||
- tests
|
|
@ -20,22 +20,14 @@ use NXP\Exception\UnknownVariableException;
|
|||
*/
|
||||
class Calculator
|
||||
{
|
||||
/** @var array<string, CustomFunction> */
|
||||
private array $functions = [];
|
||||
|
||||
/** @var array<Operator> */
|
||||
private array $operators = [];
|
||||
|
||||
/**
|
||||
* @todo PHP8: Use constructor property promotion -> public function __construct(private array $functions, private array $operators)
|
||||
*
|
||||
* @param array<string, CustomFunction> $functions
|
||||
* @param array<Operator> $operators
|
||||
*/
|
||||
public function __construct(array $functions, array $operators)
|
||||
public function __construct(private array $functions, private array $operators)
|
||||
{
|
||||
$this->functions = $functions;
|
||||
$this->operators = $operators;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,8 +8,6 @@ use ReflectionFunction;
|
|||
|
||||
class CustomFunction
|
||||
{
|
||||
public string $name = '';
|
||||
|
||||
/**
|
||||
* @var callable $function
|
||||
*/
|
||||
|
@ -26,9 +24,8 @@ class CustomFunction
|
|||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function __construct(string $name, callable $function)
|
||||
public function __construct(public string $name, callable $function)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->function = $function;
|
||||
$reflection = (new ReflectionFunction($function));
|
||||
$this->isVariadic = $reflection->isVariadic();
|
||||
|
|
|
@ -7,12 +7,6 @@ use ReflectionFunction;
|
|||
|
||||
class Operator
|
||||
{
|
||||
public string $operator = '';
|
||||
|
||||
public bool $isRightAssoc = false;
|
||||
|
||||
public int $priority = 0;
|
||||
|
||||
/**
|
||||
* @var callable(\SplStack)
|
||||
*/
|
||||
|
@ -23,11 +17,8 @@ class Operator
|
|||
/**
|
||||
* Operator constructor.
|
||||
*/
|
||||
public function __construct(string $operator, bool $isRightAssoc, int $priority, callable $function)
|
||||
public function __construct(public string $operator, public bool $isRightAssoc, public int $priority, callable $function)
|
||||
{
|
||||
$this->operator = $operator;
|
||||
$this->isRightAssoc = $isRightAssoc;
|
||||
$this->priority = $priority;
|
||||
$this->function = $function;
|
||||
$reflection = new ReflectionFunction($function);
|
||||
$this->places = $reflection->getNumberOfParameters();
|
||||
|
|
|
@ -22,22 +22,13 @@ class Token
|
|||
|
||||
public const Space = 'space';
|
||||
|
||||
public string $type = self::Literal;
|
||||
|
||||
public $value;
|
||||
|
||||
public ?string $name;
|
||||
|
||||
public ?int $paramCount = null;//to store function parameter count in stack
|
||||
|
||||
/**
|
||||
* Token constructor.
|
||||
*
|
||||
*/
|
||||
public function __construct(string $type, $value, ?string $name = null)
|
||||
public function __construct(public string $type, public mixed $value, public ?string $name = null)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->value = $value;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,17 +23,12 @@ class Tokenizer
|
|||
/** @var array<Token> */
|
||||
public array $tokens = [];
|
||||
|
||||
private string $input = '';
|
||||
|
||||
private string $numberBuffer = '';
|
||||
|
||||
private string $stringBuffer = '';
|
||||
|
||||
private bool $allowNegative = true;
|
||||
|
||||
/** @var array<Operator> */
|
||||
private array $operators = [];
|
||||
|
||||
private bool $inSingleQuotedString = false;
|
||||
|
||||
private bool $inDoubleQuotedString = false;
|
||||
|
@ -42,10 +37,8 @@ class Tokenizer
|
|||
* Tokenizer constructor.
|
||||
* @param Operator[] $operators
|
||||
*/
|
||||
public function __construct(string $input, array $operators)
|
||||
public function __construct(private string $input, private array $operators)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->operators = $operators;
|
||||
}
|
||||
|
||||
public function tokenize() : self
|
||||
|
@ -142,7 +135,7 @@ class Tokenizer
|
|||
break;
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 'e' === \strtolower($ch):
|
||||
if (\strlen($this->numberBuffer) && false !== \strpos($this->numberBuffer, '.')) {
|
||||
if (\strlen($this->numberBuffer) && \str_contains($this->numberBuffer, '.')) {
|
||||
$this->numberBuffer .= 'e';
|
||||
$this->allowNegative = false;
|
||||
|
||||
|
@ -330,7 +323,7 @@ class Tokenizer
|
|||
break;
|
||||
}
|
||||
$tokens[] = $ctoken;
|
||||
} catch (RuntimeException $e) {
|
||||
} catch (RuntimeException) {
|
||||
throw new IncorrectBracketsException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,9 +140,8 @@ class MathExecutor
|
|||
* Get a specific var
|
||||
*
|
||||
* @throws UnknownVariableException if VarNotFoundHandler is not set
|
||||
* @return int|float
|
||||
*/
|
||||
public function getVar(string $variable)
|
||||
public function getVar(string $variable) : mixed
|
||||
{
|
||||
if (! \array_key_exists($variable, $this->variables)) {
|
||||
if ($this->onVarNotFound) {
|
||||
|
@ -160,7 +159,7 @@ class MathExecutor
|
|||
*
|
||||
* @throws MathExecutorException if the value is invalid based on the default or custom validator
|
||||
*/
|
||||
public function setVar(string $variable, $value) : self
|
||||
public function setVar(string $variable, mixed $value) : self
|
||||
{
|
||||
if ($this->onVarValidation) {
|
||||
\call_user_func($this->onVarValidation, $variable, $value);
|
||||
|
@ -273,8 +272,6 @@ class MathExecutor
|
|||
|
||||
/**
|
||||
* Remove a specific operator
|
||||
*
|
||||
* @return array<Operator> of operator class names
|
||||
*/
|
||||
public function removeOperator(string $operator) : self
|
||||
{
|
||||
|
@ -380,7 +377,7 @@ class MathExecutor
|
|||
180,
|
||||
false
|
||||
],
|
||||
'^' => [static fn ($a, $b) => \pow($a, $b), 220, true],
|
||||
'^' => [static fn ($a, $b) => $a ** $b, 220, true],
|
||||
'%' => [static fn ($a, $b) => $a % $b, 180, false],
|
||||
'&&' => [static fn ($a, $b) => $a && $b, 100, false],
|
||||
'||' => [static fn ($a, $b) => $a || $b, 90, false],
|
||||
|
@ -521,7 +518,7 @@ class MathExecutor
|
|||
* Default variable validation, ensures that the value is a scalar or array.
|
||||
* @throws MathExecutorException if the value is not a scalar
|
||||
*/
|
||||
protected function defaultVarValidation(string $variable, $value) : void
|
||||
protected function defaultVarValidation(string $variable, mixed $value) : void
|
||||
{
|
||||
if (! \is_scalar($value) && ! \is_array($value) && null !== $value) {
|
||||
$type = \gettype($value);
|
||||
|
|
|
@ -31,12 +31,13 @@ class MathTest extends TestCase
|
|||
$calculator = new MathExecutor();
|
||||
|
||||
/** @var float $phpResult */
|
||||
$phpResult = 0.0;
|
||||
eval('$phpResult = ' . $expression . ';');
|
||||
|
||||
try {
|
||||
$result = $calculator->execute($expression);
|
||||
} catch (Exception $e) {
|
||||
$this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', \get_class($e), $e->getFile(), $e->getLine(), $expression));
|
||||
$this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', $e::class, $e->getFile(), $e->getLine(), $expression));
|
||||
}
|
||||
$this->assertEquals($phpResult, $result, "Expression was: {$expression}");
|
||||
}
|
||||
|
@ -47,6 +48,8 @@ class MathTest extends TestCase
|
|||
* Most tests can go in here. The idea is that each expression will be evaluated by MathExecutor and by PHP with eval.
|
||||
* The results should be the same. If they are not, then the test fails. No need to add extra test unless you are doing
|
||||
* something more complex and not a simple mathmatical expression.
|
||||
*
|
||||
* @return array<array<string>>
|
||||
*/
|
||||
public function providerExpressions()
|
||||
{
|
||||
|
@ -270,12 +273,13 @@ class MathTest extends TestCase
|
|||
}
|
||||
|
||||
/** @var float $phpResult */
|
||||
$phpResult = 0.0;
|
||||
eval('$phpResult = ' . $expected . ';');
|
||||
|
||||
try {
|
||||
$result = $calculator->execute($expression);
|
||||
} catch (Exception $e) {
|
||||
$this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', \get_class($e), $e->getFile(), $e->getLine(), $expression));
|
||||
$this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', $e::class, $e->getFile(), $e->getLine(), $expression));
|
||||
}
|
||||
$this->assertEquals($phpResult, $result, "Expression was: {$expression}");
|
||||
}
|
||||
|
@ -286,6 +290,8 @@ class MathTest extends TestCase
|
|||
* Most tests can go in here. The idea is that each expression will be evaluated by MathExecutor and by PHP with eval.
|
||||
* The results should be the same. If they are not, then the test fails. No need to add extra test unless you are doing
|
||||
* something more complex and not a simple mathmatical expression.
|
||||
*
|
||||
* @return array<array<string>>
|
||||
*/
|
||||
public function bcMathExpressions()
|
||||
{
|
||||
|
@ -505,6 +511,8 @@ class MathTest extends TestCase
|
|||
* Incorrect Expressions data provider
|
||||
*
|
||||
* These expressions should not pass validation
|
||||
*
|
||||
* @return array<array<string>>
|
||||
*/
|
||||
public function incorrectExpressions()
|
||||
{
|
||||
|
@ -592,9 +600,7 @@ class MathTest extends TestCase
|
|||
$this->assertEquals("'teststring", $calculator->execute("'\'teststring'"));
|
||||
$this->assertEquals("teststring'", $calculator->execute("'teststring\''"));
|
||||
|
||||
$calculator->addFunction('concat', static function($arg1, $arg2) {
|
||||
return $arg1 . $arg2;
|
||||
});
|
||||
$calculator->addFunction('concat', static fn ($arg1, $arg2) => $arg1 . $arg2);
|
||||
$this->assertEquals('test"ing', $calculator->execute('concat("test\"","ing")'));
|
||||
$this->assertEquals("test'ing", $calculator->execute("concat('test\'','ing')"));
|
||||
}
|
||||
|
@ -608,7 +614,7 @@ class MathTest extends TestCase
|
|||
$this->assertEquals(\max([1, 5, 2]), $calculator->execute('max(array(1, 5, 2))'));
|
||||
$calculator->addFunction('arr_with_max_elements', static function($arg1, ...$args) {
|
||||
$args = \is_array($arg1) ? $arg1 : [$arg1, ...$args];
|
||||
\usort($args, static fn ($arr1, $arr2) => \count($arr2) <=> \count($arr1));
|
||||
\usort($args, static fn ($arr1, $arr2) => (\is_countable($arr2) ? \count($arr2) : 0) <=> \count($arr1));
|
||||
|
||||
return $args[0];
|
||||
});
|
||||
|
@ -619,9 +625,7 @@ class MathTest extends TestCase
|
|||
{
|
||||
$calculator = new MathExecutor();
|
||||
|
||||
$calculator->addFunction('concat', static function($arg1, $arg2) {
|
||||
return $arg1 . $arg2;
|
||||
});
|
||||
$calculator->addFunction('concat', static fn ($arg1, $arg2) => $arg1 . $arg2);
|
||||
$this->assertEquals('testing', $calculator->execute('concat("test","ing")'));
|
||||
$this->assertEquals('testing', $calculator->execute("concat('test','ing')"));
|
||||
}
|
||||
|
@ -629,18 +633,14 @@ class MathTest extends TestCase
|
|||
public function testFunction() : void
|
||||
{
|
||||
$calculator = new MathExecutor();
|
||||
$calculator->addFunction('round', static function($arg) {
|
||||
return \round($arg);
|
||||
});
|
||||
$calculator->addFunction('round', static fn ($arg) => \round($arg));
|
||||
$this->assertEquals(\round(100 / 30), $calculator->execute('round(100/30)'));
|
||||
}
|
||||
|
||||
public function testFunctionUnlimitedParameters() : void
|
||||
{
|
||||
$calculator = new MathExecutor();
|
||||
$calculator->addFunction('give_me_an_array', static function() {
|
||||
return [5, 3, 7, 9, 8];
|
||||
});
|
||||
$calculator->addFunction('give_me_an_array', static fn () => [5, 3, 7, 9, 8]);
|
||||
$this->assertEquals(6.4, $calculator->execute('avg(give_me_an_array())'));
|
||||
$this->assertEquals(10, $calculator->execute('avg(12,8,15,5)'));
|
||||
$this->assertEquals(3, $calculator->execute('min(give_me_an_array())'));
|
||||
|
@ -657,9 +657,7 @@ class MathTest extends TestCase
|
|||
public function testFunctionOptionalParameters() : void
|
||||
{
|
||||
$calculator = new MathExecutor();
|
||||
$calculator->addFunction('round', static function($num, $precision = 0) {
|
||||
return \round($num, $precision);
|
||||
});
|
||||
$calculator->addFunction('round', static fn ($num, $precision = 0) => \round($num, $precision));
|
||||
$this->assertEquals(\round(11.176), $calculator->execute('round(11.176)'));
|
||||
$this->assertEquals(\round(11.176, 2), $calculator->execute('round(11.176,2)'));
|
||||
}
|
||||
|
@ -668,9 +666,7 @@ class MathTest extends TestCase
|
|||
{
|
||||
$calculator = new MathExecutor();
|
||||
$this->expectException(IncorrectNumberOfFunctionParametersException::class);
|
||||
$calculator->addFunction('myfunc', static function($arg1, $arg2) {
|
||||
return $arg1 + $arg2;
|
||||
});
|
||||
$calculator->addFunction('myfunc', static fn ($arg1, $arg2) => $arg1 + $arg2);
|
||||
$calculator->execute('myfunc(1)');
|
||||
}
|
||||
|
||||
|
@ -678,9 +674,7 @@ class MathTest extends TestCase
|
|||
{
|
||||
$calculator = new MathExecutor();
|
||||
$this->expectException(IncorrectNumberOfFunctionParametersException::class);
|
||||
$calculator->addFunction('myfunc', static function($arg1, $arg2) {
|
||||
return $arg1 + $arg2;
|
||||
});
|
||||
$calculator->addFunction('myfunc', static fn ($arg1, $arg2) => $arg1 + $arg2);
|
||||
$calculator->execute('myfunc(1,2,3)');
|
||||
}
|
||||
|
||||
|
@ -690,57 +684,57 @@ class MathTest extends TestCase
|
|||
$this->assertEquals(
|
||||
30,
|
||||
$calculator->execute(
|
||||
'if(100 > 99, 30, 0)'
|
||||
),
|
||||
'if(100 > 99, 30, 0)'
|
||||
),
|
||||
'Expression failed: if(100 > 99, 30, 0)'
|
||||
);
|
||||
$this->assertEquals(
|
||||
0,
|
||||
$calculator->execute(
|
||||
'if(100 < 99, 30, 0)'
|
||||
),
|
||||
'if(100 < 99, 30, 0)'
|
||||
),
|
||||
'Expression failed: if(100 < 99, 30, 0)'
|
||||
);
|
||||
$this->assertEquals(
|
||||
30,
|
||||
$calculator->execute(
|
||||
'if(98 < 99 && sin(1) < 1, 30, 0)'
|
||||
),
|
||||
'if(98 < 99 && sin(1) < 1, 30, 0)'
|
||||
),
|
||||
'Expression failed: if(98 < 99 && sin(1) < 1, 30, 0)'
|
||||
);
|
||||
$this->assertEquals(
|
||||
40,
|
||||
$calculator->execute(
|
||||
'if(98 < 99 && sin(1) < 1, max(30, 40), 0)'
|
||||
),
|
||||
'if(98 < 99 && sin(1) < 1, max(30, 40), 0)'
|
||||
),
|
||||
'Expression failed: if(98 < 99 && sin(1) < 1, max(30, 40), 0)'
|
||||
);
|
||||
$this->assertEquals(
|
||||
40,
|
||||
$calculator->execute(
|
||||
'if(98 < 99 && sin(1) < 1, if(10 > 5, max(30, 40), 1), 0)'
|
||||
),
|
||||
'if(98 < 99 && sin(1) < 1, if(10 > 5, max(30, 40), 1), 0)'
|
||||
),
|
||||
'Expression failed: if(98 < 99 && sin(1) < 1, if(10 > 5, max(30, 40), 1), 0)'
|
||||
);
|
||||
$this->assertEquals(
|
||||
20,
|
||||
$calculator->execute(
|
||||
'if(98 < 99 && sin(1) > 1, if(10 > 5, max(30, 40), 1), if(4 <= 4, 20, 21))'
|
||||
),
|
||||
'if(98 < 99 && sin(1) > 1, if(10 > 5, max(30, 40), 1), if(4 <= 4, 20, 21))'
|
||||
),
|
||||
'Expression failed: if(98 < 99 && sin(1) > 1, if(10 > 5, max(30, 40), 1), if(4 <= 4, 20, 21))'
|
||||
);
|
||||
$this->assertEquals(
|
||||
\cos(2),
|
||||
$calculator->execute(
|
||||
'if(98 < 99 && sin(1) >= 1, max(30, 40), cos(2))'
|
||||
),
|
||||
'if(98 < 99 && sin(1) >= 1, max(30, 40), cos(2))'
|
||||
),
|
||||
'Expression failed: if(98 < 99 && sin(1) >= 1, max(30, 40), cos(2))'
|
||||
);
|
||||
$this->assertEquals(
|
||||
\cos(2),
|
||||
$calculator->execute(
|
||||
'if(cos(2), cos(2), 0)'
|
||||
),
|
||||
'if(cos(2), cos(2), 0)'
|
||||
),
|
||||
'Expression failed: if(cos(2), cos(2), 0)'
|
||||
);
|
||||
$trx_amount = 100000;
|
||||
|
@ -749,15 +743,15 @@ class MathTest extends TestCase
|
|||
$this->assertEquals(
|
||||
$trx_amount * 0.03,
|
||||
$calculator->execute(
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, $trx_amount * 0.03)'
|
||||
),
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, $trx_amount * 0.03)'
|
||||
),
|
||||
'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, $trx_amount * 0.03)'
|
||||
);
|
||||
$this->assertEquals(
|
||||
$trx_amount * 0.03,
|
||||
$calculator->execute(
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
),
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
),
|
||||
'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
);
|
||||
$trx_amount = 39000;
|
||||
|
@ -765,8 +759,8 @@ class MathTest extends TestCase
|
|||
$this->assertEquals(
|
||||
$trx_amount * 0.06,
|
||||
$calculator->execute(
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
),
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
),
|
||||
'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
);
|
||||
$trx_amount = 59000;
|
||||
|
@ -774,16 +768,16 @@ class MathTest extends TestCase
|
|||
$this->assertEquals(
|
||||
$trx_amount * 0.05,
|
||||
$calculator->execute(
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
),
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
),
|
||||
'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))'
|
||||
);
|
||||
$this->expectException(IncorrectNumberOfFunctionParametersException::class);
|
||||
$this->assertEquals(
|
||||
0.0,
|
||||
$calculator->execute(
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06)'
|
||||
),
|
||||
'if($trx_amount < 40000, $trx_amount * 0.06)'
|
||||
),
|
||||
'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06)'
|
||||
);
|
||||
}
|
||||
|
@ -832,9 +826,7 @@ class MathTest extends TestCase
|
|||
$calculator = new MathExecutor();
|
||||
$calculator->addFunction(
|
||||
'round',
|
||||
static function($value, $decimals) {
|
||||
return \round($value, $decimals);
|
||||
}
|
||||
static fn ($value, $decimals) => \round($value, $decimals)
|
||||
);
|
||||
$expression = 'round(100 * 1.111111, 2)';
|
||||
$phpResult = 0;
|
||||
|
@ -848,9 +840,7 @@ class MathTest extends TestCase
|
|||
public function testFunctionsWithQuotes() : void
|
||||
{
|
||||
$calculator = new MathExecutor();
|
||||
$calculator->addFunction('concat', static function($first, $second) {
|
||||
return $first . $second;
|
||||
});
|
||||
$calculator->addFunction('concat', static fn ($first, $second) => $first . $second);
|
||||
$this->assertEquals('testing', $calculator->execute('concat("test", "ing")'));
|
||||
$this->assertEquals('testing', $calculator->execute("concat('test', 'ing')"));
|
||||
}
|
||||
|
@ -1073,14 +1063,14 @@ class MathTest extends TestCase
|
|||
/**
|
||||
* @dataProvider providerExpressionValues
|
||||
*/
|
||||
public function testCalculatingValues($expression, $value) : void
|
||||
public function testCalculatingValues(string $expression, mixed $value) : void
|
||||
{
|
||||
$calculator = new MathExecutor();
|
||||
|
||||
try {
|
||||
$result = $calculator->execute($expression);
|
||||
} catch (Exception $e) {
|
||||
$this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', \get_class($e), $e->getFile(), $e->getLine(), $expression));
|
||||
$this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', $e::class, $e->getFile(), $e->getLine(), $expression));
|
||||
}
|
||||
$this->assertEquals($value, $result, "{$expression} did not evaluate to {$value}");
|
||||
}
|
||||
|
@ -1091,6 +1081,8 @@ class MathTest extends TestCase
|
|||
* Most tests can go in here. The idea is that each expression will be evaluated by MathExecutor and by PHP directly.
|
||||
* The results should be the same. If they are not, then the test fails. No need to add extra test unless you are doing
|
||||
* something more complex and not a simple mathmatical expression.
|
||||
*
|
||||
* @return array<array<mixed>>
|
||||
*/
|
||||
public function providerExpressionValues()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue