68 lines
2.5 KiB
PHP
68 lines
2.5 KiB
PHP
<?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',
|
|
];
|
|
}
|
|
}
|