toBeInstanceOf(CouponCode::class) ->and($code->value)->toBe($value); }); }); describe('coupon code validation rules', function (): void { it('rejects invalid coupon codes', function (string $invalid): void { // WHEN / THEN expect(fn (): CouponCode => new CouponCode($invalid))->toThrow(\DomainException::class); // GIVEN })->with([ // rejects empty strings '', ' ', "\t", "\n", // rejects numbers only '12345', '67890', // rejects letters only 'ABCDE', 'FGHIJ', // rejects codes with special characters 'AB@12', 'CD#34', 'EF$56', // rejects codes that have the same digit repeated 'ABC11', 'DEF22', 'GHI33', // rejects codes with lowercase letters 'AbC12', 'dEf34', 'GhI56', ]); it('rejects codes with more/less than 3 letters or more/less than 2 digits', function (string $invalid): void { // WHEN / THEN expect(fn (): CouponCode => new CouponCode($invalid))->toThrow(\DomainException::class); // GIVEN })->with([ 'ABCD12', 'ABC123', 'ABCDE123', 'AB12', 'A1', 'AB1', 'A12', 'AB123', 'A123', 'ABC1', 'AB12C', ]); });