clqms-be/tests/feature/Calculator/CalculatorTest.php

251 lines
6.8 KiB
PHP
Raw Normal View History

<?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);
}
}