Support for better invalid expression detection and divide by zero (#30)

* Additional validation for bad expressions (*+ for example)

* Removing DivisionByZeroException testing for now

Added more unit tests.
This commit is contained in:
Bruce Wells 2018-10-25 11:54:54 -04:00 committed by GitHub
parent 4a672cfd94
commit 43f0ff3f28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 111 additions and 4 deletions

View file

@ -54,7 +54,7 @@ class Calculator
} }
} }
$result = array_pop($stack); $result = array_pop($stack);
if (!empty($stack)) { if ($result === null || ! empty($stack)) {
throw new IncorrectExpressionException(); throw new IncorrectExpressionException();
} }

View file

@ -10,6 +10,8 @@
namespace NXP\Classes\Token; namespace NXP\Classes\Token;
use NXP\Exception\IncorrectExpressionException;
/** /**
* @author Alexander Kiryukhin <alexander@symdev.org> * @author Alexander Kiryukhin <alexander@symdev.org>
*/ */
@ -41,12 +43,20 @@ class TokenDegree extends AbstractOperator
/** /**
* @param InterfaceToken[] $stack * @param InterfaceToken[] $stack
*
* @return TokenNumber * @return TokenNumber
*
* @throws \NXP\Exception\IncorrectExpressionException
*/ */
public function execute(&$stack) public function execute(&$stack)
{ {
$op2 = array_pop($stack); $op2 = array_pop($stack);
$op1 = array_pop($stack); $op1 = array_pop($stack);
if ($op1 === null || $op2 === null) {
throw new IncorrectExpressionException("Power operator requires two operators");
}
$result = $op1->getValue() ** $op2->getValue(); $result = $op1->getValue() ** $op2->getValue();
return new TokenNumber($result); return new TokenNumber($result);

View file

@ -10,6 +10,9 @@
namespace NXP\Classes\Token; namespace NXP\Classes\Token;
use NXP\Exception\IncorrectExpressionException;
use NXP\Exception\DivisionByZeroException;
/** /**
* @author Alexander Kiryukhin <alexander@symdev.org> * @author Alexander Kiryukhin <alexander@symdev.org>
*/ */
@ -41,12 +44,21 @@ class TokenDivision extends AbstractOperator
/** /**
* @param InterfaceToken[] $stack * @param InterfaceToken[] $stack
*
* @return $this * @return $this
*
* @throws \NXP\Exception\IncorrectExpressionException
* @throws \NXP\Exception\DivisionByZeroException
*/ */
public function execute(&$stack) public function execute(&$stack)
{ {
$op2 = array_pop($stack); $op2 = array_pop($stack);
$op1 = array_pop($stack); $op1 = array_pop($stack);
if ($op1 === null || $op2 === null) {
throw new IncorrectExpressionException("Division requires two operators");
}
$result = $op2->getValue() != 0 ? $op1->getValue() / $op2->getValue() : 0; $result = $op2->getValue() != 0 ? $op1->getValue() / $op2->getValue() : 0;
return new TokenNumber($result); return new TokenNumber($result);

View file

@ -10,6 +10,8 @@
namespace NXP\Classes\Token; namespace NXP\Classes\Token;
use NXP\Exception\IncorrectExpressionException;
/** /**
* @author Alexander Kiryukhin <alexander@symdev.org> * @author Alexander Kiryukhin <alexander@symdev.org>
*/ */
@ -41,12 +43,20 @@ class TokenMinus extends AbstractOperator
/** /**
* @param InterfaceToken[] $stack * @param InterfaceToken[] $stack
*
* @return $this * @return $this
*
* @throws \NXP\Exception\IncorrectExpressionException
*/ */
public function execute(&$stack) public function execute(&$stack)
{ {
$op2 = array_pop($stack); $op2 = array_pop($stack);
$op1 = array_pop($stack); $op1 = array_pop($stack);
if ($op1 === null || $op2 === null) {
throw new IncorrectExpressionException("Subtraction requires two operators");
}
$result = $op1->getValue() - $op2->getValue(); $result = $op1->getValue() - $op2->getValue();
return new TokenNumber($result); return new TokenNumber($result);

View file

@ -10,6 +10,8 @@
namespace NXP\Classes\Token; namespace NXP\Classes\Token;
use NXP\Exception\IncorrectExpressionException;
/** /**
* @author Alexander Kiryukhin <alexander@symdev.org> * @author Alexander Kiryukhin <alexander@symdev.org>
*/ */
@ -41,12 +43,20 @@ class TokenMultiply extends AbstractOperator
/** /**
* @param InterfaceToken[] $stack * @param InterfaceToken[] $stack
*
* @return $this * @return $this
*
* @throws \NXP\Exception\IncorrectExpressionException
*/ */
public function execute(&$stack) public function execute(&$stack)
{ {
$op2 = array_pop($stack); $op2 = array_pop($stack);
$op1 = array_pop($stack); $op1 = array_pop($stack);
if ($op1 === null || $op2 === null) {
throw new IncorrectExpressionException("Multiplication requires two operators");
}
$result = $op1->getValue() * $op2->getValue(); $result = $op1->getValue() * $op2->getValue();
return new TokenNumber($result); return new TokenNumber($result);

View file

@ -10,6 +10,8 @@
namespace NXP\Classes\Token; namespace NXP\Classes\Token;
use NXP\Exception\IncorrectExpressionException;
/** /**
* @author Alexander Kiryukhin <alexander@symdev.org> * @author Alexander Kiryukhin <alexander@symdev.org>
*/ */
@ -41,12 +43,20 @@ class TokenPlus extends AbstractOperator
/** /**
* @param InterfaceToken[] $stack * @param InterfaceToken[] $stack
*
* @return $this * @return $this
*
* @throws \NXP\Exception\IncorrectExpressionException
*/ */
public function execute(&$stack) public function execute(&$stack)
{ {
$op2 = array_pop($stack); $op2 = array_pop($stack);
$op1 = array_pop($stack); $op1 = array_pop($stack);
if ($op1 === null || $op2 === null) {
throw new IncorrectExpressionException("Addition requires two operators");
}
$result = $op1->getValue() + $op2->getValue(); $result = $op1->getValue() + $op2->getValue();
return new TokenNumber($result); return new TokenNumber($result);

View file

@ -0,0 +1,19 @@
<?php
/**
* This file is part of the MathExecutor package
*
* (c) Alexander Kiryukhin
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code
*/
namespace NXP\Exception;
/**
* @author Vitaliy Zhuk <zhuk2205@gmail.com>
*/
class DivisionByZeroException extends MathExecutorException
{
}

View file

@ -11,7 +11,15 @@
namespace NXP\Tests; namespace NXP\Tests;
use \NXP\MathExecutor; use NXP\MathExecutor;
use NXP\Exception\DivisionByZeroException;
use NXP\Exception\IncorrectBracketsException;
use NXP\Exception\IncorrectExpressionException;
use NXP\Exception\MathExecutorException;
use NXP\Exception\UnknownFunctionException;
use NXP\Exception\UnknownOperatorException;
use NXP\Exception\UnknownTokenException;
use NXP\Exception\UnknownVariableException;
class MathTest extends \PHPUnit_Framework_TestCase class MathTest extends \PHPUnit_Framework_TestCase
{ {
@ -27,10 +35,28 @@ class MathTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($calculator->execute($expression), $phpResult); $this->assertEquals($calculator->execute($expression), $phpResult);
} }
public function testUnknownFunctionException()
{
$calculator = new MathExecutor();
$this->expectException(UnknownFunctionException::class);
$calculator->execute('1 * fred("wilma") + 3');
}
public function testIncorrectExpressionException()
{
$calculator = new MathExecutor();
$this->expectException(IncorrectExpressionException::class);
$calculator->execute('1 * + ');
}
public function testZeroDivision() public function testZeroDivision()
{ {
$calculator = new MathExecutor(); $calculator = new MathExecutor();
$this->assertEquals($calculator->execute('1 / 0'), 0); $this->assertEquals($calculator->execute('1 / 0'), 0);
// future version with allow for optional exceptions on divide by zero
// $this->expectException(DivisionByZeroException::class);
// $calculator->execute('1 / 0');
} }
public function testExponentiation() public function testExponentiation()
@ -63,15 +89,25 @@ class MathTest extends \PHPUnit_Framework_TestCase
['(5 + 3) * -1'], ['(5 + 3) * -1'],
['2+2*2'], ['2- 2*2'],
['2-(2*2)'],
['(2- 2)*2'],
['2 + 2*2'],
['2+ 2*2'],
['(2+2)*2'], ['(2+2)*2'],
['(2+2)*-2'], ['(2 + 2)*-2'],
['(2+-2)*2'], ['(2+-2)*2'],
['sin(10) * cos(50) / min(10, 20/2)'], ['sin(10) * cos(50) / min(10, 20/2)'],
['100500 * 3.5E5'], ['100500 * 3.5E5'],
['100500 * 3.5E-5'], ['100500 * 3.5E-5'],
['-1 + -2'],
['-1+-2'],
['-1- -2'],
['-1/-2'],
['-1*-2'],
]; ];
} }