item(1055, false)); self::assertNull($access->item(LibraryFixtures::PAGE, false), 'a page is PostGuard\'s business'); self::assertNull($access->item(9999, false)); self::assertNull($access->item('abc', false)); self::assertNull($access->canList()); } /** Ruling P12: without the library right at all, library IDs read like missing IDs (no type oracle). */ public function testReadingNeedsEditPostsTheDiviLibraryRoleAndEditPost(): void { $item = LibraryFixtures::item(1055); LibraryFixtures::given([$item], ['edit_posts']); self::assertToolError(LibraryFixtures::access()->item(1055, false), 'not_found'); self::assertToolError(LibraryFixtures::access()->canList(), 'forbidden'); LibraryFixtures::given([$item]); self::assertToolError(LibraryFixtures::access(['divi_library'])->item(1055, false), 'not_found'); self::assertToolError(LibraryFixtures::access(['divi_library'])->canList(), 'forbidden'); LibraryFixtures::given([$item], ['edit_post']); $refusal = LibraryFixtures::access()->item(1055, false); self::assertToolError($refusal, 'forbidden'); self::assertStringContainsString('Bibliothekseintrag 1055', $refusal->get_error_message()); } public function testTrashedItemsCanBeRead(): void { $item = LibraryFixtures::item(1055, ['post_status' => 'trash']); LibraryFixtures::given([$item]); self::assertInstanceOf(WP_Post::class, LibraryFixtures::access()->item(1055, false)); } public function testGlobalFromTheStore(): void { $access = LibraryFixtures::access(); self::assertTrue($access->isGlobal(LibraryFixtures::item(1058))); self::assertFalse($access->isGlobal(LibraryFixtures::item(1055))); } public function testRefusalsNameNeitherTitleNorContent(): void { $item = LibraryFixtures::item(1055, ['post_status' => 'private', 'post_title' => 'Geheimer Entwurf']); foreach ([['edit_posts'], ['edit_post']] as $denied) { LibraryFixtures::given([$item], $denied); $refusal = LibraryFixtures::access()->item(1055, false); self::assertToolError($refusal, $denied === ['edit_post'] ? 'forbidden' : 'not_found'); self::assertStringNotContainsString('Geheimer Entwurf', $refusal->get_error_message()); self::assertStringNotContainsString('Geheimer Entwurf', (string) wp_json_encode($refusal->get_error_data())); } } /** Ruling P9: with the group "Divi-Bibliothek" disabled, library IDs read like IDs that do not exist. */ public function testAHiddenLibraryAnswersNotFoundLikeAMissingEntry(): void { $item = LibraryFixtures::item(1055, ['post_title' => 'Geheimer Entwurf']); LibraryFixtures::given([$item, LibraryFixtures::page('')], ['edit_post']); $hidden = new LibraryAccess(LibraryFixtures::store(), LibraryFixtures::roles(), null, static fn (): bool => false); foreach ([false, true] as $forWrite) { $refusal = $hidden->item(1055, $forWrite); self::assertToolError($refusal, 'not_found'); self::assertStringNotContainsString('Geheimer Entwurf', $refusal->get_error_message()); self::assertStringNotContainsString('Bibliothek', $refusal->get_error_message()); } self::assertNull($hidden->item(LibraryFixtures::PAGE, false), 'pages stay PostGuard\'s business'); self::assertNull($hidden->item(9999, false)); } /** Ruling P12: the refusal without the library right is byte-identical to a missing ID's. */ public function testWithoutTheLibraryRightAnEntryIsIndistinguishableFromAMissingId(): void { $schema = Mockery::mock(ContentSchema::class); $schema->allows('isManaged')->andReturn(false); foreach ([[['edit_posts'], []], [[], ['divi_library']]] as [$denied, $deniedRoles]) { LibraryFixtures::given([LibraryFixtures::item(1055, ['post_title' => 'Geheimer Entwurf'])], $denied); $refusal = LibraryFixtures::access($deniedRoles)->item(1055, false); LibraryFixtures::given([], $denied); $missing = PostGuard::editable(1055, $schema, 'post_id', true); self::assertInstanceOf(WP_Error::class, $refusal); self::assertInstanceOf(WP_Error::class, $missing); self::assertSame($missing->get_error_code(), $refusal->get_error_code()); self::assertSame($missing->get_error_message(), $refusal->get_error_message()); self::assertSame($missing->get_error_data(), $refusal->get_error_data()); } } public function testEditingNeedsSaveLibraryAPublishedItemAWritableGroupAndForGlobalsEditGlobalLibrary(): void { LibraryFixtures::given([ LibraryFixtures::item(1057), LibraryFixtures::item(1059), LibraryFixtures::item(1055, ['post_status' => 'trash']), ]); self::assertInstanceOf(WP_Post::class, LibraryFixtures::access()->item(1057, true)); self::assertToolError(LibraryFixtures::access(['save_library'])->item(1057, true), 'forbidden'); $readonly = LibraryFixtures::access([], false)->item(1057, true); self::assertToolError($readonly, 'forbidden'); self::assertStringContainsString('Divi-Bibliothek', $readonly->get_error_message()); self::assertToolError(LibraryFixtures::access()->item(1055, true), 'validation_failed'); self::assertInstanceOf(WP_Post::class, LibraryFixtures::access()->item(1059, true)); self::assertToolError(LibraryFixtures::access(['edit_global_library'])->item(1059, true), 'forbidden'); self::assertInstanceOf(WP_Post::class, LibraryFixtures::access(['edit_global_library'])->item(1057, true)); } public function testEditingNeedsEditPostOnTheEntryAndReadOnlyStillReads(): void { LibraryFixtures::given([LibraryFixtures::item(1057)], ['edit_post']); self::assertToolError(LibraryFixtures::access()->item(1057, true), 'forbidden'); LibraryFixtures::given([LibraryFixtures::item(1057)]); self::assertInstanceOf(WP_Post::class, LibraryFixtures::access([], false)->item(1057, false)); self::assertNull(LibraryFixtures::access()->writableGate()); } }