clock = new SystemClock(); $this->timer = new SystemTimer($this->clock); $this->fiberManager = new FiberManager($this->clock, $this->timer); $this->promiseFactory = new AsyncPromiseFactory($this->fiberManager); $this->asyncTimer = new AsyncTimer($this->fiberManager, $this->clock, $this->timer); $this->service = new AsyncService( $this->fiberManager, $this->promiseFactory, $this->asyncTimer, $this->clock, $this->timer ); }); it('executes async operation', function () { $fiber = $this->service->async(fn() => 'async-result'); expect($fiber->isTerminated())->toBeTrue(); expect($fiber->getReturn())->toBe('async-result'); }); it('creates promise from operation', function () { $promise = $this->service->promise(fn() => 'promise-result'); usleep(10000); // Give fiber time to execute expect($promise->await())->toBe('promise-result'); }); it('runs multiple operations in parallel with variadic', function () { $promise = $this->service->parallel( fn() => 'result1', fn() => 'result2', fn() => 'result3' ); usleep(20000); $results = $promise->await(); expect($results)->toHaveLength(3); expect($results[0])->toBe('result1'); expect($results[1])->toBe('result2'); expect($results[2])->toBe('result3'); }); it('executes operation with timeout', function () { $result = $this->service->withTimeout( fn() => 'completed', Duration::fromSeconds(1) ); expect($result)->toBe('completed'); }); it('delays execution', function () { $start = $this->clock->time(); $fiber = $this->service->delay(Duration::fromMilliseconds(50)); // Wait for delay to complete usleep(60000); $elapsed = $start->age($this->clock); expect($elapsed->toMilliseconds())->toBeGreaterThanOrEqual(50); }); it('measures execution time', function () { $promise = $this->service->measure(function () { usleep(20000); // 20ms return 'measured-result'; }); usleep(30000); $result = $promise->await(); expect($result)->toHaveKey('result'); expect($result)->toHaveKey('duration'); expect($result)->toHaveKey('milliseconds'); expect($result['result'])->toBe('measured-result'); expect($result['milliseconds'])->toBeGreaterThan(0); }); it('schedules callback after delay', function () { $executed = false; $id = $this->service->schedule( function () use (&$executed) { $executed = true; }, Duration::fromMilliseconds(20) ); expect($id)->toBeString(); // Wait for schedule to execute usleep(30000); // Note: Timer execution might vary, this is a basic check expect($id)->not->toBeEmpty(); }); it('repeats callback at interval', function () { $counter = 0; $id = $this->service->repeat( function () use (&$counter) { $counter++; }, Duration::fromMilliseconds(10) ); // Wait for multiple executions usleep(50000); // Cancel the repeat $cancelled = $this->service->cancel($id); expect($cancelled)->toBeTrue(); // Counter should have incremented at least once // Note: Exact count depends on timing expect($id)->not->toBeEmpty(); }); it('cancels scheduled operation', function () { $executed = false; $id = $this->service->schedule( function () use (&$executed) { $executed = true; }, Duration::fromMilliseconds(50) ); $cancelled = $this->service->cancel($id); expect($cancelled)->toBeTrue(); // Wait longer than scheduled delay usleep(60000); // Should still be false since we cancelled expect($executed)->toBeFalse(); }); it('batches operations with concurrency control using variadic', function () { $results = $this->service->batch( 5, // max concurrency fn() => 'batch1', fn() => 'batch2', fn() => 'batch3', fn() => 'batch4', fn() => 'batch5', fn() => 'batch6' ); expect($results)->toHaveLength(6); }); it('provides async statistics', function () { $this->service->async(fn() => 'test'); $stats = $this->service->getStats(); expect($stats)->toHaveKey('fiber_manager'); expect($stats)->toHaveKey('async_timer'); expect($stats['fiber_manager'])->toBeArray(); }); it('handles exceptions in async operations', function () { expect(function () { $fiber = $this->service->async(function () { throw new \RuntimeException('async error'); }); // Exception will be thrown when we try to get the return value $fiber->getReturn(); })->toThrow(\RuntimeException::class); }); it('chains multiple async operations', function () { $result = null; $this->service->async(function () use (&$result) { return 'step1'; }); $this->service->async(function () use (&$result) { $result = 'step2'; return $result; }); expect($result)->toBe('step2'); }); it('combines async and promise operations', function () { // Start with async fiber $fiber = $this->service->async(fn() => 10); // Continue with promise $promise = $this->service->promise(fn() => $fiber->getReturn() * 2); usleep(10000); expect($promise->await())->toBe(20); }); });