'alpha.read', 'type' => 'application', 'description' => 'Alpha application permission', 'features' => ['backup'], 'status' => 'missing', 'details' => null, ], [ 'key' => 'beta.read', 'type' => 'delegated', 'description' => 'Beta delegated permission', 'features' => ['restore'], 'status' => 'granted', 'details' => null, ], [ 'key' => 'gamma.manage', 'type' => 'application', 'description' => 'Gamma restore permission', 'features' => ['backup', 'restore'], 'status' => 'error', 'details' => null, ], ]; $state = TenantRequiredPermissionsViewModelBuilder::normalizeFilterState([ 'status' => 'all', 'type' => 'all', 'features' => [], 'search' => '', ]); $filtered = TenantRequiredPermissionsViewModelBuilder::applyFilterState($permissions, $state); expect(array_column($filtered, 'key'))->toBe([ 'alpha.read', 'gamma.manage', 'beta.read', ]); $missingState = TenantRequiredPermissionsViewModelBuilder::normalizeFilterState([ 'status' => 'missing', 'type' => 'all', 'features' => ['backup'], 'search' => '', ]); $missing = TenantRequiredPermissionsViewModelBuilder::applyFilterState($permissions, $missingState); expect(array_column($missing, 'key'))->toBe([ 'alpha.read', 'gamma.manage', ]); $presentDelegatedState = TenantRequiredPermissionsViewModelBuilder::normalizeFilterState([ 'status' => 'present', 'type' => 'delegated', 'features' => [], 'search' => '', ]); $presentDelegated = TenantRequiredPermissionsViewModelBuilder::applyFilterState($permissions, $presentDelegatedState); expect(array_column($presentDelegated, 'key'))->toBe([ 'beta.read', ]); $searchState = TenantRequiredPermissionsViewModelBuilder::normalizeFilterState([ 'status' => 'all', 'type' => 'all', 'features' => [], 'search' => 'RESTORE', ]); $search = TenantRequiredPermissionsViewModelBuilder::applyFilterState($permissions, $searchState); expect(array_column($search, 'key'))->toBe([ 'gamma.manage', ]); });