toHaveCount(5); expect(QuarantineStatus::PENDING)->toBeInstanceOf(QuarantineStatus::class); expect(QuarantineStatus::SCANNING)->toBeInstanceOf(QuarantineStatus::class); expect(QuarantineStatus::APPROVED)->toBeInstanceOf(QuarantineStatus::class); expect(QuarantineStatus::REJECTED)->toBeInstanceOf(QuarantineStatus::class); expect(QuarantineStatus::EXPIRED)->toBeInstanceOf(QuarantineStatus::class); }); it('identifies pending status', function () { expect(QuarantineStatus::PENDING->isPending())->toBeTrue(); expect(QuarantineStatus::SCANNING->isPending())->toBeFalse(); expect(QuarantineStatus::APPROVED->isPending())->toBeFalse(); }); it('identifies scanning status', function () { expect(QuarantineStatus::SCANNING->isScanning())->toBeTrue(); expect(QuarantineStatus::PENDING->isScanning())->toBeFalse(); expect(QuarantineStatus::APPROVED->isScanning())->toBeFalse(); }); it('identifies approved status', function () { expect(QuarantineStatus::APPROVED->isApproved())->toBeTrue(); expect(QuarantineStatus::PENDING->isApproved())->toBeFalse(); expect(QuarantineStatus::REJECTED->isApproved())->toBeFalse(); }); it('identifies rejected status', function () { expect(QuarantineStatus::REJECTED->isRejected())->toBeTrue(); expect(QuarantineStatus::PENDING->isRejected())->toBeFalse(); expect(QuarantineStatus::APPROVED->isRejected())->toBeFalse(); }); it('identifies expired status', function () { expect(QuarantineStatus::EXPIRED->isExpired())->toBeTrue(); expect(QuarantineStatus::PENDING->isExpired())->toBeFalse(); expect(QuarantineStatus::SCANNING->isExpired())->toBeFalse(); }); it('identifies final statuses', function () { expect(QuarantineStatus::APPROVED->isFinal())->toBeTrue(); expect(QuarantineStatus::REJECTED->isFinal())->toBeTrue(); expect(QuarantineStatus::EXPIRED->isFinal())->toBeTrue(); expect(QuarantineStatus::PENDING->isFinal())->toBeFalse(); expect(QuarantineStatus::SCANNING->isFinal())->toBeFalse(); }); it('allows transition from PENDING to SCANNING', function () { $status = QuarantineStatus::PENDING; expect($status->canTransitionTo(QuarantineStatus::SCANNING))->toBeTrue(); }); it('allows transition from PENDING to EXPIRED', function () { $status = QuarantineStatus::PENDING; expect($status->canTransitionTo(QuarantineStatus::EXPIRED))->toBeTrue(); }); it('rejects transition from PENDING to APPROVED', function () { $status = QuarantineStatus::PENDING; expect($status->canTransitionTo(QuarantineStatus::APPROVED))->toBeFalse(); }); it('rejects transition from PENDING to REJECTED', function () { $status = QuarantineStatus::PENDING; expect($status->canTransitionTo(QuarantineStatus::REJECTED))->toBeFalse(); }); it('allows transition from SCANNING to APPROVED', function () { $status = QuarantineStatus::SCANNING; expect($status->canTransitionTo(QuarantineStatus::APPROVED))->toBeTrue(); }); it('allows transition from SCANNING to REJECTED', function () { $status = QuarantineStatus::SCANNING; expect($status->canTransitionTo(QuarantineStatus::REJECTED))->toBeTrue(); }); it('allows transition from SCANNING to EXPIRED', function () { $status = QuarantineStatus::SCANNING; expect($status->canTransitionTo(QuarantineStatus::EXPIRED))->toBeTrue(); }); it('rejects transition from SCANNING to PENDING', function () { $status = QuarantineStatus::SCANNING; expect($status->canTransitionTo(QuarantineStatus::PENDING))->toBeFalse(); }); it('rejects all transitions from APPROVED', function () { $status = QuarantineStatus::APPROVED; expect($status->canTransitionTo(QuarantineStatus::PENDING))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::SCANNING))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::REJECTED))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::EXPIRED))->toBeFalse(); }); it('rejects all transitions from REJECTED', function () { $status = QuarantineStatus::REJECTED; expect($status->canTransitionTo(QuarantineStatus::PENDING))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::SCANNING))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::APPROVED))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::EXPIRED))->toBeFalse(); }); it('rejects all transitions from EXPIRED', function () { $status = QuarantineStatus::EXPIRED; expect($status->canTransitionTo(QuarantineStatus::PENDING))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::SCANNING))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::APPROVED))->toBeFalse(); expect($status->canTransitionTo(QuarantineStatus::REJECTED))->toBeFalse(); }); it('has string values matching case names', function () { expect(QuarantineStatus::PENDING->value)->toBe('pending'); expect(QuarantineStatus::SCANNING->value)->toBe('scanning'); expect(QuarantineStatus::APPROVED->value)->toBe('approved'); expect(QuarantineStatus::REJECTED->value)->toBe('rejected'); expect(QuarantineStatus::EXPIRED->value)->toBe('expired'); }); it('follows expected state machine flow', function () { // Happy path: PENDING → SCANNING → APPROVED expect(QuarantineStatus::PENDING->canTransitionTo(QuarantineStatus::SCANNING))->toBeTrue(); expect(QuarantineStatus::SCANNING->canTransitionTo(QuarantineStatus::APPROVED))->toBeTrue(); // Rejection path: PENDING → SCANNING → REJECTED expect(QuarantineStatus::PENDING->canTransitionTo(QuarantineStatus::SCANNING))->toBeTrue(); expect(QuarantineStatus::SCANNING->canTransitionTo(QuarantineStatus::REJECTED))->toBeTrue(); // Timeout path: PENDING → EXPIRED expect(QuarantineStatus::PENDING->canTransitionTo(QuarantineStatus::EXPIRED))->toBeTrue(); // Scan timeout: SCANNING → EXPIRED expect(QuarantineStatus::SCANNING->canTransitionTo(QuarantineStatus::EXPIRED))->toBeTrue(); }); });