count($groupCount)->create(); // 创建一个测试用户 $user = User::factory()->create(); // 随机将用户分配到一些分组(0-3个) $userGroupCount = rand(0, min(3, $groupCount)); $userGroups = $groups->random(min($userGroupCount, $groupCount)); $user->groups()->attach($userGroups->pluck('id')); // 创建随机数量的全局文档(1-10个) $globalDocCount = rand(1, 10); $globalDocs = Document::factory()->count($globalDocCount)->global()->create(); // 为每个分组创建随机数量的专用文档(0-5个) $dedicatedDocs = collect(); foreach ($groups as $group) { $docCount = rand(0, 5); $docs = Document::factory()->count($docCount)->dedicated($group->id)->create(); $dedicatedDocs = $dedicatedDocs->merge($docs); } // 执行查询:获取用户可访问的文档 $accessibleDocs = Document::accessibleBy($user)->get(); // 验证:所有全局文档都应该在结果中 foreach ($globalDocs as $globalDoc) { expect($accessibleDocs->contains('id', $globalDoc->id)) ->toBeTrue("全局文档 {$globalDoc->id} 应该对用户可见"); } // 验证:用户所属分组的专用文档都应该在结果中 $userGroupIds = $userGroups->pluck('id')->toArray(); $userDedicatedDocs = $dedicatedDocs->whereIn('group_id', $userGroupIds); foreach ($userDedicatedDocs as $doc) { expect($accessibleDocs->contains('id', $doc->id)) ->toBeTrue("用户分组的专用文档 {$doc->id} 应该对用户可见"); } // 验证:其他分组的专用文档不应该在结果中 $otherGroupDocs = $dedicatedDocs->whereNotIn('group_id', $userGroupIds); foreach ($otherGroupDocs as $doc) { expect($accessibleDocs->contains('id', $doc->id)) ->toBeFalse("其他分组的专用文档 {$doc->id} 不应该对用户可见"); } // 验证:结果数量应该等于全局文档数 + 用户分组的专用文档数 $expectedCount = $globalDocCount + $userDedicatedDocs->count(); expect($accessibleDocs->count()) ->toBe($expectedCount, "可访问文档数量应该是 {$expectedCount}"); // 清理数据以便下一次迭代 Document::query()->delete(); User::query()->delete(); Group::query()->delete(); } })->group('property-based-test'); /** * Feature: knowledge-base-system, Property 8: 其他分组文档隔离 * * 对于任何用户和任何不属于该用户分组的专用知识库文档, * 该文档不应该出现在用户的可访问文档列表中 * * Validates: Requirements 3.4 */ test('property 8: 其他分组的专用文档应该被隔离,不出现在用户的可访问列表中', function () { // 运行 100 次迭代 for ($i = 0; $i < 100; $i++) { // 创建至少 2 个分组 $groupCount = rand(2, 5); $groups = Group::factory()->count($groupCount)->create(); // 创建一个测试用户 $user = User::factory()->create(); // 将用户分配到部分分组(至少留一个分组不分配) $userGroupCount = rand(1, $groupCount - 1); $userGroups = $groups->random($userGroupCount); $user->groups()->attach($userGroups->pluck('id')); // 获取用户不属于的分组 $otherGroups = $groups->diff($userGroups); // 为其他分组创建专用文档 $otherGroupDocs = collect(); foreach ($otherGroups as $group) { $docCount = rand(1, 5); $docs = Document::factory()->count($docCount)->dedicated($group->id)->create(); $otherGroupDocs = $otherGroupDocs->merge($docs); } // 执行查询:获取用户可访问的文档 $accessibleDocs = Document::accessibleBy($user)->get(); // 验证:其他分组的所有专用文档都不应该在结果中 foreach ($otherGroupDocs as $doc) { expect($accessibleDocs->contains('id', $doc->id)) ->toBeFalse("其他分组的专用文档 {$doc->id}(分组 {$doc->group_id})不应该对用户可见"); } // 额外验证:确保结果中没有任何其他分组的文档 $otherGroupIds = $otherGroups->pluck('id')->toArray(); $leakedDocs = $accessibleDocs->filter(function ($doc) use ($otherGroupIds) { return $doc->type === 'dedicated' && in_array($doc->group_id, $otherGroupIds); }); expect($leakedDocs->count()) ->toBe(0, "不应该有任何其他分组的专用文档泄露到用户的可访问列表中"); // 清理数据以便下一次迭代 Document::query()->delete(); User::query()->delete(); Group::query()->delete(); } })->group('property-based-test');