allows('adminsAreStudioAdmins')->andReturn($studio); $access->allows('adminsAreInstructors')->andReturn($instructor); return new RoleManager($access); } public function testRegisterAddsInitHookAndCapFilter(): void { Functions\expect('add_action') ->once() ->with('init', \Mockery::any()); Functions\expect('add_filter') ->once() ->with('user_has_cap', \Mockery::any(), 10, 1); (new RoleManager())->register(); } public function testGrantsStudioCapsToAdministrators(): void { $result = $this->roleManager()->grantStudioCapsToAdministrators(['manage_options' => true]); foreach (RoleManager::STUDIO_ADMIN_CAPS as $cap) { self::assertTrue($result[$cap], "administrator should be granted {$cap}"); } } public function testGrantsInstructorCapsToAdministrators(): void { $result = $this->roleManager()->grantStudioCapsToAdministrators(['manage_options' => true]); // A single-instructor studio owner runs as an administrator and also // teaches, so they get the instructor caps — notably manage_availability, // which is not part of the studio-admin set. self::assertTrue($result[RoleManager::CAP_MANAGE_AVAILABILITY], 'administrator should be able to manage availability'); foreach (RoleManager::INSTRUCTOR_CAPS as $cap) { self::assertTrue($result[$cap], "administrator should be granted {$cap}"); } } public function testStudioGrantDisabledWithholdsStudioCapsFromAdministrators(): void { $result = $this->roleManager(studio: false)->grantStudioCapsToAdministrators(['manage_options' => true]); // manage_instructors is studio-only, so it disappears when the grant is off. self::assertArrayNotHasKey(RoleManager::CAP_MANAGE_INSTRUCTORS, $result); // Instructor caps remain because that grant is still on. self::assertTrue($result[RoleManager::CAP_MANAGE_AVAILABILITY]); } public function testInstructorGrantDisabledWithholdsInstructorCapsFromAdministrators(): void { $result = $this->roleManager(instructor: false)->grantStudioCapsToAdministrators(['manage_options' => true]); // manage_availability is instructor-only, so it disappears when the grant is off. self::assertArrayNotHasKey(RoleManager::CAP_MANAGE_AVAILABILITY, $result); // Studio caps remain because that grant is still on. self::assertTrue($result[RoleManager::CAP_MANAGE_INSTRUCTORS]); } public function testDoesNotGrantCapsToNonAdministrators(): void { $result = $this->roleManager()->grantStudioCapsToAdministrators(['read' => true]); self::assertArrayNotHasKey(RoleManager::CAP_MANAGE_OFFERINGS, $result); self::assertSame(['read' => true], $result); } public function testCreateRolesSkipsExistingRoles(): void { Functions\when('get_role')->alias(static fn() => new \stdClass()); Functions\expect('add_role')->never(); (new RoleManager())->createRoles(); } public function testCreateRolesAddsInstructorRoleWithCorrectCaps(): void { Functions\when('get_role')->alias(static function (string $role): ?object { return $role === RoleManager::INSTRUCTOR ? null : new \stdClass(); }); Functions\expect('add_role') ->once() ->with( RoleManager::INSTRUCTOR, \Mockery::any(), \Mockery::on(static function (array $caps): bool { return ($caps['read'] ?? false) === true && ($caps[RoleManager::CAP_MANAGE_AVAILABILITY] ?? false) === true && ($caps[RoleManager::CAP_VIEW_LESSONS] ?? false) === true; }) ); (new RoleManager())->createRoles(); } public function testCreateRolesAddsStudioAdminRoleWithCorrectCaps(): void { Functions\when('get_role')->alias(static function (string $role): ?object { return $role === RoleManager::STUDIO_ADMIN ? null : new \stdClass(); }); Functions\expect('add_role') ->once() ->with( RoleManager::STUDIO_ADMIN, \Mockery::any(), \Mockery::on(static function (array $caps): bool { return ($caps['read'] ?? false) === true && ($caps[RoleManager::CAP_MANAGE_INSTRUCTORS] ?? false) === true && ($caps[RoleManager::CAP_MANAGE_OFFERINGS] ?? false) === true && ($caps[RoleManager::CAP_MANAGE_POLICIES] ?? false) === true && ($caps[RoleManager::CAP_MANAGE_BILLING] ?? false) === true && ($caps[RoleManager::CAP_VIEW_ALL_PAYMENTS] ?? false) === true; }) ); (new RoleManager())->createRoles(); } public function testCreateRolesAddsStudentRoleWithCorrectCaps(): void { Functions\when('get_role')->alias(static function (string $role): ?object { return $role === RoleManager::STUDENT ? null : new \stdClass(); }); Functions\expect('add_role') ->once() ->with( RoleManager::STUDENT, \Mockery::any(), \Mockery::on(static function (array $caps): bool { return ($caps['read'] ?? false) === true && ($caps[RoleManager::CAP_BOOK_LESSON] ?? false) === true && ($caps[RoleManager::CAP_VIEW_LESSONS] ?? false) === true; }) ); (new RoleManager())->createRoles(); } }