게시글 컬렉션 */ private function makePosts(int $count): Collection { return collect(range(1, $count))->map(function (int $i) { $post = new Post; $post->id = 1000 + $i; $post->is_notice = false; $post->parent_id = null; return $post; }); } /** * 컬렉션을 렌더링해 순번만 뽑아냅니다. * * @param int $page 현재 페이지 * @param int $perPage 페이지당 건수 * @param BoundedCount $total 총 건수 + 정확도 * @param string $direction 정렬 방향 * @return array 순번 목록 */ private function numbersFor(int $page, int $perPage, BoundedCount $total, string $direction = 'desc'): array { $paginator = new LengthAwarePaginator( $this->makePosts($perPage), max($total->total(), $page * $perPage), $perPage, $page, ); $collection = new PostCollection($paginator); $collection->setTotalNormalPosts($total); $collection->setOrderDirection($direction); $rendered = $collection->toArray(request()); return collect($rendered['data'])->pluck('number')->all(); } /** * 총 건수가 잘리지 않았으면 순번은 지금까지처럼 정확해야 합니다. */ public function test_총건수가_정확하면_순번은_총건수부터_내림차순이다(): void { $numbers = $this->numbersFor( page: 1, perPage: 5, total: new BoundedCount(120, TotalRelation::Exact, 10000), ); $this->assertSame([120, 119, 118, 117, 116], $numbers); } /** * 총 건수가 잘렸으면 순번을 지어내지 않아야 합니다. */ public function test_총건수가_잘리면_순번은_null_이다(): void { $numbers = $this->numbersFor( page: 1, perPage: 5, total: new BoundedCount(10000, TotalRelation::AtLeast, 10000), ); $this->assertSame([null, null, null, null, null], $numbers); } /** * 상한을 넘어선 깊은 페이지에서도 0·음수가 나오지 않아야 합니다. */ public function test_상한을_넘은_페이지에서_0이나_음수_순번이_없다(): void { foreach ([501, 502, 601] as $page) { $numbers = $this->numbersFor( page: $page, perPage: 20, total: new BoundedCount(10000, TotalRelation::AtLeast, 10000), ); foreach ($numbers as $number) { $this->assertNotIsInt( $number, "{$page} 페이지에서 상한 총 건수로 역산한 순번이 그대로 나왔습니다." ); } } } /** * 오름차순은 offset 기반이라 총 건수가 잘려도 그대로 정확해야 합니다. */ public function test_오름차순_순번은_총건수가_잘려도_유지된다(): void { $numbers = $this->numbersFor( page: 3, perPage: 5, total: new BoundedCount(10000, TotalRelation::AtLeast, 10000), direction: 'asc', ); $this->assertSame([11, 12, 13, 14, 15], $numbers); } /** * PHPUnit 11 에는 assertNotIsInt 가 없으므로 의미를 그대로 옮겨 둡니다. * * @param mixed $value 검사 대상 * @param string $message 실패 메시지 */ private function assertNotIsInt(mixed $value, string $message = ''): void { $this->assertFalse(is_int($value), $message); } }