$slug, 'name' => ['ko' => '답글 차단 테스트 게시판', 'en' => 'Reply Block Test Board'], 'is_active' => true, 'use_comment' => true, 'use_reply' => true, 'max_reply_depth' => 3, 'secret_mode' => 'disabled', 'blocked_keywords' => [], ]; } protected function setUp(): void { parent::setUp(); $slug = $this->board->slug; // posts.write 권한 보유 사용자 (답글 작성 폼 진입 권한) $this->writer = User::factory()->create(); $userRole = Role::where('identifier', 'user')->first(); if ($userRole) { $writePerm = Permission::firstOrCreate( ['identifier' => "sirsoft-board.{$slug}.posts.write"], ['name' => ['ko' => '게시글 작성', 'en' => 'Write Posts'], 'type' => 'user'] ); $userRole->permissions()->syncWithoutDetaching([$writePerm->id]); $this->writer->roles()->attach($userRole->id); } } private function formMetaUrl(int $parentId): string { return "/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/form-meta?parent_id={$parentId}"; } private function formDataUrl(int $parentId): string { return "/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/form-data?parent_id={$parentId}"; } // ========================================== // 블라인드 부모글 // ========================================== public function test_form_meta_blocks_blinded_parent_and_hides_original(): void { $parentId = $this->createTestPost([ 'title' => '블라인드 부모 제목 SECRET', 'content' => '블라인드 부모 본문 SECRET', 'status' => 'blinded', 'trigger_type' => 'report', ]); $response = $this->actingAs($this->writer, 'sanctum') ->getJson($this->formMetaUrl($parentId)); $response->assertNotFound(); $this->assertStringNotContainsString('블라인드 부모 제목 SECRET', $this->decodedContent($response)); $this->assertStringNotContainsString('블라인드 부모 본문 SECRET', $this->decodedContent($response)); } public function test_form_data_blocks_blinded_parent_and_hides_original(): void { $parentId = $this->createTestPost([ 'title' => '블라인드 부모 제목 SECRET', 'content' => '블라인드 부모 본문 SECRET', 'status' => 'blinded', 'trigger_type' => 'report', ]); $response = $this->actingAs($this->writer, 'sanctum') ->getJson($this->formDataUrl($parentId)); $response->assertNotFound(); $this->assertStringNotContainsString('블라인드 부모 제목 SECRET', $this->decodedContent($response)); $this->assertStringNotContainsString('블라인드 부모 본문 SECRET', $this->decodedContent($response)); } // ========================================== // 삭제된 부모글 // ========================================== public function test_form_meta_blocks_deleted_parent_and_hides_original(): void { $parentId = $this->createTestPost([ 'title' => '삭제 부모 제목 SECRET', 'content' => '삭제 부모 본문 SECRET', 'status' => 'deleted', 'deleted_at' => now(), ]); $response = $this->actingAs($this->writer, 'sanctum') ->getJson($this->formMetaUrl($parentId)); $response->assertNotFound(); $this->assertStringNotContainsString('삭제 부모 제목 SECRET', $this->decodedContent($response)); $this->assertStringNotContainsString('삭제 부모 본문 SECRET', $this->decodedContent($response)); } public function test_form_data_blocks_deleted_parent_and_hides_original(): void { $parentId = $this->createTestPost([ 'title' => '삭제 부모 제목 SECRET', 'content' => '삭제 부모 본문 SECRET', 'status' => 'deleted', 'deleted_at' => now(), ]); $response = $this->actingAs($this->writer, 'sanctum') ->getJson($this->formDataUrl($parentId)); $response->assertNotFound(); $this->assertStringNotContainsString('삭제 부모 제목 SECRET', $this->decodedContent($response)); $this->assertStringNotContainsString('삭제 부모 본문 SECRET', $this->decodedContent($response)); } // ========================================== // 정상 부모글 (회귀 방지 — 차단되면 안 됨) // ========================================== public function test_form_meta_allows_published_parent(): void { $parentId = $this->createTestPost([ 'title' => '정상 부모 제목', 'content' => '정상 부모 본문', 'status' => 'published', ]); $response = $this->actingAs($this->writer, 'sanctum') ->getJson($this->formMetaUrl($parentId)); $response->assertOk(); $response->assertJsonPath('data.parent_post.title', '정상 부모 제목'); } /** * JSON 응답 본문을 유니코드 이스케이프 해제하여 반환합니다. * * Laravel JSON 응답은 한글을 \uXXXX로 직렬화하므로, 원문 노출 여부 검증 시 * 디코딩 후 비교해야 합니다. * * @param \Illuminate\Testing\TestResponse $response 테스트 응답 * @return string 디코딩된 본문 문자열 */ private function decodedContent($response): string { return json_encode($response->json(), JSON_UNESCAPED_UNICODE) ?: ''; } }