@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Services\SimulationTaxRuleExpression;
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class SimulationTaxRuleExpressionTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function it_evaluates_a_whitelisted_dag_with_exact_decimal_arithmetic_and_explicit_rounding(): void
|
||||
{
|
||||
$definition = $this->definition();
|
||||
$result = (new SimulationTaxRuleExpression)->evaluate($definition, ['base' => '1234.56'], ['rate' => '0.16']);
|
||||
|
||||
self::assertSame('determinate', $result['status']);
|
||||
self::assertSame('19753/100', $result['result']);
|
||||
self::assertCount(4, $result['steps']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_reports_missing_values_as_indeterminate_without_defaults(): void
|
||||
{
|
||||
$result = (new SimulationTaxRuleExpression)->evaluate($this->definition(), [], []);
|
||||
|
||||
self::assertSame('indeterminate', $result['status']);
|
||||
self::assertNull($result['result']);
|
||||
self::assertSame(['input:base', 'parameter:rate'], $result['missing']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_rejects_cycles_unknown_operations_and_undeclared_fields(): void
|
||||
{
|
||||
$engine = new SimulationTaxRuleExpression;
|
||||
$cycle = ['language' => 'investmoz.tax.v1', 'nodes' => ['a' => ['op' => 'add', 'args' => ['b', 'b']], 'b' => ['op' => 'add', 'args' => ['a', 'a']]], 'result' => 'a'];
|
||||
$unknown = ['language' => 'investmoz.tax.v1', 'nodes' => ['a' => ['op' => 'execute', 'code' => 'x']], 'result' => 'a'];
|
||||
$extra = ['language' => 'investmoz.tax.v1', 'nodes' => ['a' => ['op' => 'literal', 'value' => '1', 'formula' => 'x']], 'result' => 'a'];
|
||||
|
||||
foreach ([$cycle, $unknown, $extra] as $invalid) {
|
||||
try {
|
||||
$engine->validate($invalid);
|
||||
self::fail('Invalid DSL was accepted.');
|
||||
} catch (InvalidArgumentException) {
|
||||
self::assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array<string,mixed> */
|
||||
private function definition(): array
|
||||
{
|
||||
return [
|
||||
'language' => 'investmoz.tax.v1',
|
||||
'nodes' => [
|
||||
'base' => ['op' => 'input', 'key' => 'base'],
|
||||
'rate' => ['op' => 'parameter', 'key' => 'rate'],
|
||||
'raw' => ['op' => 'multiply', 'args' => ['base', 'rate']],
|
||||
'tax' => ['op' => 'round', 'args' => ['raw'], 'scale' => 2, 'mode' => 'HALF_UP'],
|
||||
],
|
||||
'result' => 'tax',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user