makePartial(); $queries = []; $db->allows('get_results')->andReturnUsing(static function (string $sql) use (&$queries): array { $queries[] = $sql; return [ ['ID' => '1053', 'post_status' => 'draft', 'post_type' => 'page'], ['ID' => '1061', 'post_status' => 'private', 'post_type' => 'et_header_layout'], ]; }); $rows = (new GlobalUsages($db))->rows(1058); self::assertSame( [ ['id' => 1053, 'status' => 'draft', 'type' => 'page'], ['id' => 1061, 'status' => 'private', 'type' => 'et_header_layout'], ], $rows ); self::assertCount(1, $queries); self::assertStringStartsWith('SELECT ID, post_status, post_type FROM', $queries[0]); self::assertStringContainsString("LIKE '%\"globalModule\":\"1058\"%'", $queries[0]); self::assertStringContainsString("post_status NOT IN ('trash', 'auto-draft', 'inherit')", $queries[0]); self::assertStringContainsString("post_type <> 'revision'", $queries[0]); self::assertStringNotContainsString('LIMIT', $queries[0]); self::assertStringNotContainsString('post_content,', $queries[0]); } /** Audit L4: readable posts with title, unreadable ones only counted. */ public function testListsReadablePostsAndCountsTheOthers(): void { $usages = LibraryFixtures::usages([ ['id' => 1053, 'status' => 'draft', 'type' => 'page'], ['id' => 1061, 'status' => 'private', 'type' => 'et_header_layout'], ]); Functions\when('get_post')->alias( static fn (int $id): WP_Post => new WP_Post(['ID' => $id, 'post_title' => 'Titel ' . $id]) ); Functions\when('current_user_can')->alias( static fn (string $cap, int $id): bool => $id !== 1061 ); $report = $usages->report(1058); self::assertSame(2, $report->count); self::assertSame( [['post_id' => 1053, 'title' => 'Titel 1053', 'status' => 'draft', 'type' => 'page']], $report->items ); self::assertSame(1, $report->hidden); self::assertSame(1, $report->live); self::assertSame([], $report->blocked); self::assertSame(1, $report->blockedHidden); self::assertSame( ['affected' => $report->items, 'affected_count' => 2, 'hidden_count' => 1, 'blocked_hidden_count' => 1], $report->details() ); } /** Audit L1: rights are checked in chunks, each with its own primed cache that is dropped afterwards. */ public function testChecksLargeSetsInChunksAndReleasesTheCache(): void { $usages = LibraryFixtures::usages(LibraryFixtures::rows(range(1, 450))); $primed = []; Functions\when('_prime_post_caches')->alias(static function (array $ids) use (&$primed): void { $primed[] = count($ids); }); $deleted = 0; Functions\when('wp_cache_delete')->alias(static function () use (&$deleted): bool { ++$deleted; return true; }); Functions\when('get_post')->justReturn(null); Functions\when('current_user_can')->alias(static fn (string $cap, int $id): bool => $id % 100 !== 0); $report = $usages->report(1058); self::assertSame([GlobalUsages::CHUNK, GlobalUsages::CHUNK, 50], $primed); self::assertSame(450, $deleted); self::assertSame(450, $report->count); self::assertCount(GlobalUsages::LIMIT, $report->items); self::assertSame(4, $report->hidden); self::assertSame(4, $report->blockedHidden); self::assertTrue($report->blocks()); } /** Audit L1: above the hard cap nothing is checked for edit_post, and the report blocks. */ public function testAboveTheHardCapNoPostIsCheckedForEditing(): void { $usages = LibraryFixtures::usages(LibraryFixtures::rows(range(1, GlobalUsages::HARD_CAP + 1))); Functions\when('get_post')->justReturn(null); $asked = []; Functions\when('current_user_can')->alias(static function (string $cap) use (&$asked): bool { $asked[$cap] = ($asked[$cap] ?? 0) + 1; return true; }); $report = $usages->report(1058); self::assertTrue($report->tooMany); self::assertTrue($report->blocks()); self::assertArrayNotHasKey('edit_post', $asked); self::assertSame(GlobalUsages::CHECK_CAP, $asked['read_post']); } public function testAListingSkipsTheEditChecks(): void { $usages = LibraryFixtures::usages(LibraryFixtures::rows([1053])); Functions\when('get_post')->justReturn(null); Functions\when('current_user_can')->alias(static fn (string $cap): bool => $cap !== 'edit_post'); $report = $usages->report(1058, false); self::assertFalse($report->blocks()); self::assertSame(['affected', 'affected_count'], array_keys($report->listing())); } }