from())->toBe(0) ->and($p->to())->toBe(49) ->and($p->pageSize())->toBe(50) ->and($p->pageNumber())->toBe(1) ->and($p->pageSizeVo())->toEqual(new PageSize(50)) ->and($p->pageNumberVo())->toEqual(new PageNumber(1)) ->and((string) $p)->toBe('Pagination{from=0, to=49}'); }); it('creates pagination using ofPage with Value Objects', function (): void { // GIVEN $pageNumber = new PageNumber(2); $pageSize = new PageSize(25); // WHEN $p = Pagination::ofPage($pageNumber, $pageSize); // THEN expect($p->from())->toBe(25) ->and($p->to())->toBe(49) ->and($p->pageSize())->toBe(25) ->and($p->pageNumber())->toBe(2) ->and($p->pageNumberVo())->toEqual($pageNumber) ->and($p->pageSizeVo())->toEqual($pageSize); // GIVEN $pageNumber2 = new PageNumber(3); $pageSize2 = new PageSize(10); // WHEN $p2 = Pagination::ofPage($pageNumber2, $pageSize2); // THEN expect($p2->from())->toBe(20) ->and($p2->to())->toBe(29) ->and($p2->pageSize())->toBe(10) ->and($p2->pageNumber())->toBe(3); }); it('creates first page with default page size', function (): void { // WHEN $p = Pagination::firstPage(); // THEN expect($p->from())->toBe(0) ->and($p->to())->toBe(49) ->and($p->pageSize())->toBe(50) ->and($p->pageNumber())->toBe(1); }); it('creates first page with explicit page size', function (): void { // GIVEN $pageSize = new PageSize(20); // WHEN $p = Pagination::firstPage($pageSize); // THEN expect($p->from())->toBe(0) ->and($p->to())->toBe(19) ->and($p->pageSize())->toBe(20) ->and($p->pageNumber())->toBe(1); }); it('creates pagination using ofOffsetAndLimit', function (): void { // GIVEN $offset = 10; $limit = 15; // WHEN $p = Pagination::ofOffsetAndLimit($offset, $limit); // THEN expect($p->from())->toBe(10) ->and($p->to())->toBe(24) ->and($p->pageSize())->toBe(15); }); it('checks equality with another Pagination instance', function (): void { // GIVEN $p1 = Pagination::ofPage(new PageNumber(1), new PageSize(20)); $p2 = Pagination::ofPage(new PageNumber(1), new PageSize(20)); $p3 = Pagination::ofPage(new PageNumber(2), new PageSize(20)); // THEN expect($p1->equals($p2))->toBeTrue() ->and($p1->equals($p3))->toBeFalse() ->and($p1->equals(null))->toBeFalse() ->and($p1->equals('pagination'))->toBeFalse(); }); it('throws exception on negative from index', function (): void { // GIVEN / WHEN expect(fn () => new Pagination(-1, 10)) // THEN ->toThrow(InvalidArgumentException::class, 'From index must be non-negative'); }); it('throws exception on negative to index', function (): void { // GIVEN / WHEN expect(fn () => new Pagination(0, -1)) // THEN ->toThrow(InvalidArgumentException::class, 'To index must be non-negative'); }); it('throws exception when to is less than or equal to from', function (): void { // GIVEN / WHEN expect(fn () => new Pagination(10, 10)) // THEN ->toThrow(InvalidArgumentException::class, 'To index must be greater than from index'); }); it('throws exception when page size exceeds max', function (): void { // GIVEN / WHEN expect(fn () => new Pagination(0, 10001)) // THEN ->toThrow(InvalidArgumentException::class, 'Page size must be less than or equal to 10000'); }); it('throws exception in ofOffsetAndLimit on negative offset', function (): void { // GIVEN / WHEN expect(fn () => Pagination::ofOffsetAndLimit(-1, 10)) // THEN ->toThrow(InvalidArgumentException::class, 'Offset must be non-negative'); }); it('throws exception in ofOffsetAndLimit on non-positive limit', function (): void { // GIVEN / WHEN expect(fn () => Pagination::ofOffsetAndLimit(0, 0)) // THEN ->toThrow(InvalidArgumentException::class, 'Limit must be positive and non-zero'); }); });