index)->toBe(0); expect($metadata->size)->toBe($size); expect($metadata->hash)->toBe($hash); expect($metadata->uploaded)->toBeFalse(); }); it('rejects negative chunk index', function () { $hash = ChunkHash::fromData('test'); $size = Byte::fromKilobytes(100); expect(fn() => ChunkMetadata::create(-1, $size, $hash)) ->toThrow(InvalidArgumentException::class); }); it('rejects zero chunk size', function () { $hash = ChunkHash::fromData('test'); $size = Byte::fromBytes(0); expect(fn() => ChunkMetadata::create(0, $size, $hash)) ->toThrow(InvalidArgumentException::class); }); it('marks chunk as uploaded', function () { $hash = ChunkHash::fromData('test'); $size = Byte::fromKilobytes(100); $metadata = ChunkMetadata::create(0, $size, $hash); expect($metadata->isUploaded())->toBeFalse(); $uploaded = $metadata->withUploaded(); expect($uploaded->isUploaded())->toBeTrue(); expect($uploaded->index)->toBe($metadata->index); expect($uploaded->size)->toBe($metadata->size); expect($uploaded->hash)->toBe($metadata->hash); }); it('preserves immutability when marking uploaded', function () { $hash = ChunkHash::fromData('test'); $size = Byte::fromKilobytes(100); $original = ChunkMetadata::create(0, $size, $hash); $uploaded = $original->withUploaded(); expect($original->isUploaded())->toBeFalse(); expect($uploaded->isUploaded())->toBeTrue(); }); it('converts to array correctly', function () { $hash = ChunkHash::fromData('test chunk data'); $size = Byte::fromKilobytes(100); $metadata = ChunkMetadata::create(5, $size, $hash); $array = $metadata->toArray(); expect($array['index'])->toBe(5); expect($array['size'])->toBe(102400); // 100KB in bytes expect($array['size_human'])->toBeString(); expect($array['hash'])->toBe($hash->toString()); expect($array['uploaded'])->toBeFalse(); }); it('includes uploaded status in array', function () { $hash = ChunkHash::fromData('test'); $size = Byte::fromKilobytes(100); $metadata = ChunkMetadata::create(0, $size, $hash)->withUploaded(); $array = $metadata->toArray(); expect($array['uploaded'])->toBeTrue(); }); it('handles different chunk sizes', function () { $hash = ChunkHash::fromData('test'); $small = ChunkMetadata::create(0, Byte::fromBytes(1), $hash); $medium = ChunkMetadata::create(1, Byte::fromMegabytes(5), $hash); $large = ChunkMetadata::create(2, Byte::fromMegabytes(100), $hash); expect($small->size->toBytes())->toBe(1); expect($medium->size->toBytes())->toBe(5242880); // 5MB expect($large->size->toBytes())->toBe(104857600); // 100MB }); it('maintains chunk index ordering', function () { $hash = ChunkHash::fromData('test'); $size = Byte::fromKilobytes(100); $chunks = [ ChunkMetadata::create(0, $size, $hash), ChunkMetadata::create(5, $size, $hash), ChunkMetadata::create(10, $size, $hash), ]; expect($chunks[0]->index)->toBe(0); expect($chunks[1]->index)->toBe(5); expect($chunks[2]->index)->toBe(10); }); });