ldc-boutique-cnc-sable/tests/Unit/Domain/Models/ValueObjects/DiscountValueTest.php
2026-10-27 09:58:12 +01:00

230 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Domain\Models\ValueObjects;
use Domain\Enums\DiscountType;
use Domain\Models\ValueObjects\DiscountValue;
use Money\Currency;
use Money\Money;
describe('DiscountValue', function () {
function getDiscountMoney(int $amount, string $currency = 'EUR'): Money
{
return new Money($amount, new Currency($currency));
}
it('can instantiate from amount', function () {
// GIVEN
$amount = getDiscountMoney(100);
// WHEN
$vo = DiscountValue::fromAmount($amount);
// THEN
expect($vo)->toBeInstanceOf(DiscountValue::class);
expect($vo->isPercentage())->toBeFalse();
});
it('can instantiate from percentage', function () {
// GIVEN
$rate = 20;
// WHEN
$vo = DiscountValue::fromPercentage($rate);
// THEN
expect($vo)->toBeInstanceOf(DiscountValue::class);
expect($vo->isPercentage())->toBeTrue();
});
it('throws exception if percentage is negative', function () {
// GIVEN
// WHEN
$action = fn () => DiscountValue::fromPercentage(-1);
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('throws exception if percentage is greater than 100', function () {
// GIVEN
$rate = 101;
// WHEN
$action = fn () => DiscountValue::fromPercentage($rate);
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('throws exception if amount is negative', function () {
// GIVEN
$amount = getDiscountMoney(-1);
// WHEN
$action = fn () => DiscountValue::fromAmount($amount);
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('returns the correct value for amount discount', function () {
// GIVEN
$amount = getDiscountMoney(50);
// WHEN
$vo = DiscountValue::fromAmount($amount);
// THEN
expect($vo->value())->toEqual($amount);
});
it('returns the correct value for percentage discount', function () {
// GIVEN
$rate = 20;
// WHEN
$vo = DiscountValue::fromPercentage($rate);
// THEN
expect($vo->value())->toBe($rate);
});
it('returns the correct percentage rate', function () {
// GIVEN
$percentage = 20;
// WHEN
$vo = DiscountValue::fromPercentage($percentage);
// THEN
expect($vo->getPercentageRate())->toBe(0.2);
});
it('throws exception when getting percentage rate from amount discount', function () {
// GIVEN
$amount = getDiscountMoney(100);
$vo = DiscountValue::fromAmount($amount);
// WHEN
$action = fn () => $vo->getPercentageRate();
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('returns the correct amount', function () {
// GIVEN
$amount = getDiscountMoney(100);
// WHEN
$vo = DiscountValue::fromAmount($amount);
// THEN
expect($vo->getAmount())->toEqual($amount);
});
it('throws exception when getting amount from percentage discount', function () {
// GIVEN
$vo = DiscountValue::fromPercentage(10);
// WHEN
$action = fn () => $vo->getAmount();
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('calculates discount amount correctly for percentage', function () {
// GIVEN
$basePrice = getDiscountMoney(1000);
$vo = DiscountValue::fromPercentage(20); // 20%
// WHEN
$result = $vo->calculateDiscountAmount($basePrice);
// THEN
expect($result->getAmount())->toBe('200');
});
it('calculates discount amount correctly for fixed amount', function () {
// GIVEN
$basePrice = getDiscountMoney(1000);
$vo = DiscountValue::fromAmount(getDiscountMoney(50));
// WHEN
$result = $vo->calculateDiscountAmount($basePrice);
// THEN
expect($result->getAmount())->toBe('50');
});
it('throws exception on currency mismatch when calculating discount', function () {
// GIVEN
$basePrice = getDiscountMoney(1000, 'EUR');
$vo = DiscountValue::fromAmount(getDiscountMoney(50, 'USD'));
// WHEN
$action = fn () => $vo->calculateDiscountAmount($basePrice);
// THEN
expect($action)->toThrow(\DomainException::class);
});
});
describe('DiscountValue exceptions', function (): void {
it('throws when percentage is missing for percent type', function (): void {
// GIVEN
$reflection = new \ReflectionClass(DiscountValue::class);
$method = $reflection->getMethod('__construct');
$vo = $reflection->newInstanceWithoutConstructor();
// WHEN
$action = fn () => $method->invoke($vo, DiscountType::PERCENT, null, null);
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('throws when amount is missing for amount type', function (): void {
// GIVEN
$reflection = new \ReflectionClass(DiscountValue::class);
$method = $reflection->getMethod('__construct');
$vo = $reflection->newInstanceWithoutConstructor();
// WHEN
$action = fn () => $method->invoke($vo, DiscountType::AMOUNT, null, null);
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('throws unexpected value if percentage is null', function (): void {
// GIVEN
$reflection = new \ReflectionClass(DiscountValue::class);
$vo = $reflection->newInstanceWithoutConstructor();
$prop = $reflection->getProperty('type');
$prop->setValue($vo, DiscountType::PERCENT);
$prop2 = $reflection->getProperty('percentage');
$prop2->setValue($vo, null);
// WHEN
$action = fn () => $vo->getPercentage();
// THEN
expect($action)->toThrow(\DomainException::class);
});
it('throws unexpected value if amount is null', function (): void {
// GIVEN
$reflection = new \ReflectionClass(DiscountValue::class);
$vo = $reflection->newInstanceWithoutConstructor();
$prop = $reflection->getProperty('type');
$prop->setValue($vo, DiscountType::AMOUNT);
$prop2 = $reflection->getProperty('amount');
$prop2->setValue($vo, null);
// WHEN
$action = fn () => $vo->getAmount();
// THEN
expect($action)->toThrow(\DomainException::class);
});
});