Files
breadcrumb-the-shire/tests/Unit/Module/AddressBookAuthorizationPolicyTest.php
fs ef72b34c40 feat: module architecture improvements — session keys, dependency graph, event dispatcher, deactivation hooks
Six targeted improvements to the modular monolith platform:

1. Fix AddressBook session key prefix to follow module.<id>.* convention
2. Move ADDRESS_BOOK_VIEW permission constant from core PermissionService into module
3. Add declarative JSON schema for module manifests (.agents/contracts/)
4. Add `requires` field with missing-dependency and circular-dependency detection
5. Add lightweight fire-and-forget event dispatcher (user.created/deleted/login/logout)
6. Add module deactivation hook interface and CLI script (bin/module-deactivate.php)

Includes 15 new architecture/unit tests covering all new functionality.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:20:13 +01:00

88 lines
3.1 KiB
PHP

<?php
namespace MintyPHP\Tests\Unit\Module;
use MintyPHP\Module\AddressBook\AddressBookAuthorizationPolicy;
use MintyPHP\Service\Access\AuthorizationPolicyInterface;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Tests\Service\Access\AuthorizationPolicyTestSupport;
use PHPUnit\Framework\TestCase;
/**
* @covers \MintyPHP\Module\AddressBook\AddressBookAuthorizationPolicy
*/
final class AddressBookAuthorizationPolicyTest extends TestCase
{
use AuthorizationPolicyTestSupport;
public function testImplementsInterface(): void
{
$policy = new AddressBookAuthorizationPolicy($this->createMock(PermissionService::class));
self::assertInstanceOf(AuthorizationPolicyInterface::class, $policy);
}
public function testSupportsOwnAbility(): void
{
$policy = new AddressBookAuthorizationPolicy($this->createMock(PermissionService::class));
self::assertTrue($policy->supports(AddressBookAuthorizationPolicy::ABILITY_VIEW));
}
public function testDoesNotSupportOtherAbilities(): void
{
$policy = new AddressBookAuthorizationPolicy($this->createMock(PermissionService::class));
self::assertFalse($policy->supports('ops.admin.jobs.view'));
self::assertFalse($policy->supports(''));
self::assertFalse($policy->supports('ops.address_book.view')); // old ability string
}
public function testAllowedWithPermission(): void
{
$permissionService = $this->permissionGatewayAllowing([
5 => [AddressBookAuthorizationPolicy::PERMISSION_KEY],
]);
$policy = new AddressBookAuthorizationPolicy($permissionService);
$decision = $policy->authorize(AddressBookAuthorizationPolicy::ABILITY_VIEW, [
'actor_user_id' => 5,
]);
self::assertTrue($decision->isAllowed());
}
public function testDeniedWithoutPermission(): void
{
$permissionService = $this->permissionGatewayAllowing([5 => []]);
$policy = new AddressBookAuthorizationPolicy($permissionService);
$decision = $policy->authorize(AddressBookAuthorizationPolicy::ABILITY_VIEW, [
'actor_user_id' => 5,
]);
$this->assertForbiddenDecision($decision);
}
public function testDeniedWithZeroActorId(): void
{
$permissionService = $this->createMock(PermissionService::class);
$permissionService->expects($this->never())->method('userHas');
$policy = new AddressBookAuthorizationPolicy($permissionService);
$decision = $policy->authorize(AddressBookAuthorizationPolicy::ABILITY_VIEW, [
'actor_user_id' => 0,
]);
$this->assertForbiddenDecision($decision);
}
public function testDeniedWithMissingActorId(): void
{
$permissionService = $this->createMock(PermissionService::class);
$permissionService->expects($this->never())->method('userHas');
$policy = new AddressBookAuthorizationPolicy($permissionService);
$decision = $policy->authorize(AddressBookAuthorizationPolicy::ABILITY_VIEW, []);
$this->assertForbiddenDecision($decision);
}
}