251 lines
6.8 KiB
PHP
251 lines
6.8 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Feature\Calculator;
|
||
|
|
|
||
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
||
|
|
use App\Services\CalculatorService;
|
||
|
|
|
||
|
|
class CalculatorTest extends CIUnitTestCase
|
||
|
|
{
|
||
|
|
protected CalculatorService $calculator;
|
||
|
|
|
||
|
|
public function setUp(): void {
|
||
|
|
parent::setUp();
|
||
|
|
$this->calculator = new CalculatorService();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test basic arithmetic operations
|
||
|
|
*/
|
||
|
|
public function testBasicArithmetic() {
|
||
|
|
// Addition and multiplication precedence
|
||
|
|
$result = $this->calculator->calculate('1+2*3');
|
||
|
|
$this->assertEquals(7.0, $result);
|
||
|
|
|
||
|
|
// Parentheses
|
||
|
|
$result = $this->calculator->calculate('(1+2)*3');
|
||
|
|
$this->assertEquals(9.0, $result);
|
||
|
|
|
||
|
|
// Division
|
||
|
|
$result = $this->calculator->calculate('10/2');
|
||
|
|
$this->assertEquals(5.0, $result);
|
||
|
|
|
||
|
|
// Power
|
||
|
|
$result = $this->calculator->calculate('2^3');
|
||
|
|
$this->assertEquals(8.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test formula with simple variables
|
||
|
|
*/
|
||
|
|
public function testFormulaWithVariables() {
|
||
|
|
$formula = '{result} * {factor}';
|
||
|
|
$variables = ['result' => 50, 'factor' => 2];
|
||
|
|
|
||
|
|
$result = $this->calculator->calculate($formula, $variables);
|
||
|
|
$this->assertEquals(100.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test formula with gender variable (numeric values)
|
||
|
|
*/
|
||
|
|
public function testFormulaWithGenderNumeric() {
|
||
|
|
// Gender: 0=Unknown, 1=Female, 2=Male
|
||
|
|
$formula = '50 + {gender} * 10';
|
||
|
|
|
||
|
|
// Male (2)
|
||
|
|
$result = $this->calculator->calculate($formula, ['gender' => 2]);
|
||
|
|
$this->assertEquals(70.0, $result);
|
||
|
|
|
||
|
|
// Female (1)
|
||
|
|
$result = $this->calculator->calculate($formula, ['gender' => 1]);
|
||
|
|
$this->assertEquals(60.0, $result);
|
||
|
|
|
||
|
|
// Unknown (0)
|
||
|
|
$result = $this->calculator->calculate($formula, ['gender' => 0]);
|
||
|
|
$this->assertEquals(50.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test formula with gender variable (string values)
|
||
|
|
*/
|
||
|
|
public function testFormulaWithGenderString() {
|
||
|
|
$formula = '50 + {gender} * 10';
|
||
|
|
|
||
|
|
// String values
|
||
|
|
$result = $this->calculator->calculate($formula, ['gender' => 'male']);
|
||
|
|
$this->assertEquals(70.0, $result);
|
||
|
|
|
||
|
|
$result = $this->calculator->calculate($formula, ['gender' => 'female']);
|
||
|
|
$this->assertEquals(60.0, $result);
|
||
|
|
|
||
|
|
$result = $this->calculator->calculate($formula, ['gender' => 'unknown']);
|
||
|
|
$this->assertEquals(50.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test mathematical functions
|
||
|
|
*/
|
||
|
|
public function testMathFunctions() {
|
||
|
|
// Square root
|
||
|
|
$result = $this->calculator->calculate('sqrt(16)');
|
||
|
|
$this->assertEquals(4.0, $result);
|
||
|
|
|
||
|
|
// Sine
|
||
|
|
$result = $this->calculator->calculate('sin(pi/2)');
|
||
|
|
$this->assertEqualsWithDelta(1.0, $result, 0.0001);
|
||
|
|
|
||
|
|
// Cosine
|
||
|
|
$result = $this->calculator->calculate('cos(0)');
|
||
|
|
$this->assertEquals(1.0, $result);
|
||
|
|
|
||
|
|
// Logarithm
|
||
|
|
$result = $this->calculator->calculate('log(100)');
|
||
|
|
$this->assertEqualsWithDelta(4.60517, $result, 0.0001);
|
||
|
|
|
||
|
|
// Natural log (ln)
|
||
|
|
$result = $this->calculator->calculate('ln(2.71828)');
|
||
|
|
$this->assertEqualsWithDelta(1.0, $result, 0.0001);
|
||
|
|
|
||
|
|
// Exponential
|
||
|
|
$result = $this->calculator->calculate('exp(1)');
|
||
|
|
$this->assertEqualsWithDelta(2.71828, $result, 0.0001);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test formula validation
|
||
|
|
*/
|
||
|
|
public function testFormulaValidation() {
|
||
|
|
// Valid formula
|
||
|
|
$validation = $this->calculator->validate('{result} * 2 + 5');
|
||
|
|
$this->assertTrue($validation['valid']);
|
||
|
|
$this->assertNull($validation['error']);
|
||
|
|
|
||
|
|
// Invalid formula
|
||
|
|
$validation = $this->calculator->validate('{result} * * 2');
|
||
|
|
$this->assertFalse($validation['valid']);
|
||
|
|
$this->assertNotNull($validation['error']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test variable extraction
|
||
|
|
*/
|
||
|
|
public function testExtractVariables() {
|
||
|
|
$formula = '{result} * {factor} + {gender} - {age}';
|
||
|
|
$variables = $this->calculator->extractVariables($formula);
|
||
|
|
|
||
|
|
$this->assertEquals(['result', 'factor', 'gender', 'age'], $variables);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test missing variable error
|
||
|
|
*/
|
||
|
|
public function testMissingVariableError() {
|
||
|
|
$this->expectException(\Exception::class);
|
||
|
|
$this->expectExceptionMessage("Missing variable value for: missing_var");
|
||
|
|
|
||
|
|
$this->calculator->calculate('{result} + {missing_var}', ['result' => 10]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test invalid formula syntax error
|
||
|
|
*/
|
||
|
|
public function testInvalidFormulaError() {
|
||
|
|
$this->expectException(\Exception::class);
|
||
|
|
$this->expectExceptionMessage("Invalid formula");
|
||
|
|
|
||
|
|
$this->calculator->calculate('1 + * 2');
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test complex formula with multiple variables
|
||
|
|
*/
|
||
|
|
public function testComplexFormula() {
|
||
|
|
// Complex formula: (result * factor / 100) + (gender * 5) - (age * 0.1)
|
||
|
|
$formula = '({result} * {factor} / 100) + ({gender} * 5) - ({age} * 0.1)';
|
||
|
|
$variables = [
|
||
|
|
'result' => 200,
|
||
|
|
'factor' => 10,
|
||
|
|
'gender' => 2, // Male
|
||
|
|
'age' => 30
|
||
|
|
];
|
||
|
|
|
||
|
|
// Expected: (200 * 10 / 100) + (2 * 5) - (30 * 0.1) = 20 + 10 - 3 = 27
|
||
|
|
$result = $this->calculator->calculate($formula, $variables);
|
||
|
|
$this->assertEquals(27.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test calculation from TestDefCal definition
|
||
|
|
*/
|
||
|
|
public function testCalculateFromDefinition() {
|
||
|
|
$calcDef = [
|
||
|
|
'FormulaCode' => '{result} * {factor} + 10',
|
||
|
|
'Factor' => 2,
|
||
|
|
];
|
||
|
|
|
||
|
|
$testValues = [
|
||
|
|
'result' => 50,
|
||
|
|
];
|
||
|
|
|
||
|
|
// Expected: 50 * 2 + 10 = 110
|
||
|
|
$result = $this->calculator->calculateFromDefinition($calcDef, $testValues);
|
||
|
|
$this->assertEquals(110.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test calculation with all optional variables
|
||
|
|
*/
|
||
|
|
public function testCalculateWithAllVariables() {
|
||
|
|
$calcDef = [
|
||
|
|
'FormulaCode' => '{result} + {factor} + {gender} + {age} + {ref_low} + {ref_high}',
|
||
|
|
'Factor' => 5,
|
||
|
|
];
|
||
|
|
|
||
|
|
$testValues = [
|
||
|
|
'result' => 10,
|
||
|
|
'gender' => 1,
|
||
|
|
'age' => 25,
|
||
|
|
'ref_low' => 5,
|
||
|
|
'ref_high' => 15,
|
||
|
|
];
|
||
|
|
|
||
|
|
// Expected: 10 + 5 + 1 + 25 + 5 + 15 = 61
|
||
|
|
$result = $this->calculator->calculateFromDefinition($calcDef, $testValues);
|
||
|
|
$this->assertEquals(61.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test empty formula error
|
||
|
|
*/
|
||
|
|
public function testEmptyFormulaError() {
|
||
|
|
$this->expectException(\Exception::class);
|
||
|
|
$this->expectExceptionMessage("No formula defined");
|
||
|
|
|
||
|
|
$calcDef = [
|
||
|
|
'FormulaCode' => '',
|
||
|
|
'Factor' => 1,
|
||
|
|
];
|
||
|
|
|
||
|
|
$this->calculator->calculateFromDefinition($calcDef, ['result' => 10]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test implicit multiplication
|
||
|
|
*/
|
||
|
|
public function testImplicitMultiplication() {
|
||
|
|
// math-parser supports implicit multiplication (2x means 2*x)
|
||
|
|
$result = $this->calculator->calculate('2*3');
|
||
|
|
$this->assertEquals(6.0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Test decimal calculations
|
||
|
|
*/
|
||
|
|
public function testDecimalCalculations() {
|
||
|
|
$formula = '{result} / 3';
|
||
|
|
$result = $this->calculator->calculate($formula, ['result' => 10]);
|
||
|
|
$this->assertEqualsWithDelta(3.33333, $result, 0.0001);
|
||
|
|
}
|
||
|
|
}
|