generate(); expect($sessionId)->toBeInstanceOf(UploadSessionId::class); expect(strlen($sessionId->value))->toBe(32); // 16 bytes = 32 hex chars }); it('generates hex-encoded session ids', function () { $randomGen = new class implements RandomGenerator { public function bytes(int $length): string { return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); $sessionId = $generator->generate(); // Verify it's valid hex expect(ctype_xdigit($sessionId->value))->toBeTrue(); }); it('generates unique session ids', function () { $randomGen = new class implements RandomGenerator { public function bytes(int $length): string { return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); $id1 = $generator->generate(); $id2 = $generator->generate(); $id3 = $generator->generate(); expect($id1->equals($id2))->toBeFalse(); expect($id1->equals($id3))->toBeFalse(); expect($id2->equals($id3))->toBeFalse(); }); it('generates 100 unique session ids', function () { $randomGen = new class implements RandomGenerator { public function bytes(int $length): string { return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); $sessionIds = []; for ($i = 0; $i < 100; $i++) { $sessionIds[] = $generator->generate()->value; } $uniqueIds = array_unique($sessionIds); expect(count($uniqueIds))->toBe(100); }); it('requests 16 bytes from random generator', function () { $randomGen = new class implements RandomGenerator { public int $lastRequestedLength = 0; public function bytes(int $length): string { $this->lastRequestedLength = $length; return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); $generator->generate(); expect($randomGen->lastRequestedLength)->toBe(16); }); it('uses RandomGenerator bytes method', function () { $randomGen = new class implements RandomGenerator { public bool $bytesCalled = false; public function bytes(int $length): string { $this->bytesCalled = true; return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); $generator->generate(); expect($randomGen->bytesCalled)->toBeTrue(); }); it('produces alphanumeric session ids', function () { $randomGen = new class implements RandomGenerator { public function bytes(int $length): string { return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); for ($i = 0; $i < 10; $i++) { $sessionId = $generator->generate(); expect(ctype_alnum($sessionId->value))->toBeTrue(); } }); it('generates consistent length session ids', function () { $randomGen = new class implements RandomGenerator { public function bytes(int $length): string { return random_bytes($length); } public function int(int $min, int $max): int { return random_int($min, $max); } public function float(): float { return (float) random_int(0, PHP_INT_MAX) / PHP_INT_MAX; } }; $generator = new UploadSessionIdGenerator($randomGen); $lengths = []; for ($i = 0; $i < 50; $i++) { $sessionId = $generator->generate(); $lengths[] = strlen($sessionId->value); } $uniqueLengths = array_unique($lengths); expect(count($uniqueLengths))->toBe(1); expect($uniqueLengths[0])->toBe(32); }); });