update test
This commit is contained in:
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace HyperfTest\Cases\Unit\Service;
|
||||
|
||||
use App\Model\Platform;
|
||||
use App\Model\Store;
|
||||
use App\Model\User;
|
||||
use App\Model\UserDataScope;
|
||||
use App\Service\ScopeBitmapService;
|
||||
use Hyperf\DbConnection\Db;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class ScopeBitmapServiceTest extends TestCase
|
||||
{
|
||||
protected ScopeBitmapService $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->service = new ScopeBitmapService();
|
||||
}
|
||||
|
||||
protected function runInCoroutine(callable $callback): void
|
||||
{
|
||||
if (\Swoole\Coroutine::getCid() > 0) {
|
||||
$callback();
|
||||
return;
|
||||
}
|
||||
|
||||
$exception = null;
|
||||
\Swoole\Coroutine\run(static function () use ($callback, &$exception): void {
|
||||
try {
|
||||
$callback();
|
||||
} catch (\Throwable $e) {
|
||||
$exception = $e;
|
||||
}
|
||||
});
|
||||
if ($exception) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
// --- encode/decode 双向转换 ---
|
||||
|
||||
public function test_encode_empty_array_returns_empty_string(): void
|
||||
{
|
||||
$this->assertSame('', $this->service->encode([]));
|
||||
}
|
||||
|
||||
public function test_encode_single_store_id(): void
|
||||
{
|
||||
$bitmap = $this->service->encode([1]);
|
||||
$this->assertSame([1], $this->service->decode($bitmap));
|
||||
}
|
||||
|
||||
public function test_encode_multiple_store_ids(): void
|
||||
{
|
||||
$ids = [1, 3, 5, 8, 10];
|
||||
$bitmap = $this->service->encode($ids);
|
||||
$decoded = $this->service->decode($bitmap);
|
||||
$this->assertSame($ids, $decoded);
|
||||
}
|
||||
|
||||
public function test_encode_decode_large_ids(): void
|
||||
{
|
||||
$ids = [1, 100, 500, 1000];
|
||||
$bitmap = $this->service->encode($ids);
|
||||
$decoded = $this->service->decode($bitmap);
|
||||
$this->assertSame($ids, $decoded);
|
||||
}
|
||||
|
||||
public function test_decode_empty_string_returns_empty_array(): void
|
||||
{
|
||||
$this->assertSame([], $this->service->decode(''));
|
||||
}
|
||||
|
||||
public function test_encode_preserves_order(): void
|
||||
{
|
||||
// 编码时乱序,解码后应升序
|
||||
$bitmap = $this->service->encode([5, 1, 3]);
|
||||
$this->assertSame([1, 3, 5], $this->service->decode($bitmap));
|
||||
}
|
||||
|
||||
// --- has 检查 ---
|
||||
|
||||
public function test_has_returns_true_for_existing_id(): void
|
||||
{
|
||||
$bitmap = $this->service->encode([1, 5, 10]);
|
||||
$this->assertTrue($this->service->has($bitmap, 1));
|
||||
$this->assertTrue($this->service->has($bitmap, 5));
|
||||
$this->assertTrue($this->service->has($bitmap, 10));
|
||||
}
|
||||
|
||||
public function test_has_returns_false_for_missing_id(): void
|
||||
{
|
||||
$bitmap = $this->service->encode([1, 5, 10]);
|
||||
$this->assertFalse($this->service->has($bitmap, 2));
|
||||
$this->assertFalse($this->service->has($bitmap, 6));
|
||||
$this->assertFalse($this->service->has($bitmap, 11));
|
||||
}
|
||||
|
||||
public function test_has_returns_false_for_id_beyond_bitmap_length(): void
|
||||
{
|
||||
$bitmap = $this->service->encode([1]);
|
||||
$this->assertFalse($this->service->has($bitmap, 100));
|
||||
}
|
||||
|
||||
public function test_has_returns_false_for_empty_bitmap(): void
|
||||
{
|
||||
$this->assertFalse($this->service->has('', 1));
|
||||
}
|
||||
|
||||
// --- merge 合并 ---
|
||||
|
||||
public function test_merge_two_bitmaps(): void
|
||||
{
|
||||
$bitmap1 = $this->service->encode([1, 3]);
|
||||
$bitmap2 = $this->service->encode([2, 4]);
|
||||
$merged = $this->service->merge($bitmap1, $bitmap2);
|
||||
|
||||
$this->assertSame([1, 2, 3, 4], $this->service->decode($merged));
|
||||
}
|
||||
|
||||
public function test_merge_overlapping_bitmaps(): void
|
||||
{
|
||||
$bitmap1 = $this->service->encode([1, 3, 5]);
|
||||
$bitmap2 = $this->service->encode([3, 5, 7]);
|
||||
$merged = $this->service->merge($bitmap1, $bitmap2);
|
||||
|
||||
$this->assertSame([1, 3, 5, 7], $this->service->decode($merged));
|
||||
}
|
||||
|
||||
public function test_merge_different_length_bitmaps(): void
|
||||
{
|
||||
$bitmap1 = $this->service->encode([1]);
|
||||
$bitmap2 = $this->service->encode([100]);
|
||||
$merged = $this->service->merge($bitmap1, $bitmap2);
|
||||
|
||||
$this->assertTrue($this->service->has($merged, 1));
|
||||
$this->assertTrue($this->service->has($merged, 100));
|
||||
}
|
||||
|
||||
public function test_merge_with_empty_bitmaps(): void
|
||||
{
|
||||
$bitmap = $this->service->encode([1, 3]);
|
||||
$merged = $this->service->merge($bitmap, '');
|
||||
$this->assertSame([1, 3], $this->service->decode($merged));
|
||||
}
|
||||
|
||||
public function test_merge_all_empty_returns_empty(): void
|
||||
{
|
||||
$this->assertSame('', $this->service->merge('', ''));
|
||||
}
|
||||
|
||||
// --- buildForUser(需要数据库) ---
|
||||
|
||||
public function test_build_for_user_with_store_scope(): void
|
||||
{
|
||||
$this->runInCoroutine(function (): void {
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
$user = User::query()->first();
|
||||
|
||||
// 查已有 store
|
||||
$stores = Store::query()->limit(2)->pluck('id')->toArray();
|
||||
if (count($stores) < 2) {
|
||||
$this->markTestSkipped('需要至少 2 个 store 记录');
|
||||
}
|
||||
|
||||
// 插入 store 类型的 scope
|
||||
foreach ($stores as $store_id) {
|
||||
UserDataScope::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'scope_type' => 'store',
|
||||
'scope_id' => $store_id,
|
||||
]);
|
||||
}
|
||||
|
||||
$bitmap = $this->service->buildForUser($user->id);
|
||||
$this->assertNotEmpty($bitmap);
|
||||
|
||||
foreach ($stores as $store_id) {
|
||||
$this->assertTrue($this->service->has($bitmap, $store_id));
|
||||
}
|
||||
} finally {
|
||||
Db::rollBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_build_for_user_with_company_scope(): void
|
||||
{
|
||||
$this->runInCoroutine(function (): void {
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
$user = User::query()->first();
|
||||
|
||||
// 查找有 store 的 company
|
||||
$store = Store::query()->first();
|
||||
if (!$store) {
|
||||
$this->markTestSkipped('需要至少 1 个 store 记录');
|
||||
}
|
||||
|
||||
UserDataScope::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'scope_type' => 'company',
|
||||
'scope_id' => $store->company_id,
|
||||
]);
|
||||
|
||||
$bitmap = $this->service->buildForUser($user->id);
|
||||
$this->assertNotEmpty($bitmap);
|
||||
|
||||
// 该 company 下的 store 应在 bitmap 中
|
||||
$company_stores = Store::query()
|
||||
->where('company_id', $store->company_id)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
foreach ($company_stores as $sid) {
|
||||
$this->assertTrue($this->service->has($bitmap, $sid));
|
||||
}
|
||||
} finally {
|
||||
Db::rollBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_build_for_user_with_no_scopes_returns_empty(): void
|
||||
{
|
||||
$this->runInCoroutine(function (): void {
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
$user = User::query()->first();
|
||||
// 不插入 scope
|
||||
$bitmap = $this->service->buildForUser($user->id);
|
||||
$this->assertSame('', $bitmap);
|
||||
} finally {
|
||||
Db::rollBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_build_for_user_with_mixed_scopes(): void
|
||||
{
|
||||
$this->runInCoroutine(function (): void {
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
$user = User::query()->first();
|
||||
$store = Store::query()->first();
|
||||
if (!$store) {
|
||||
$this->markTestSkipped('需要至少 1 个 store 记录');
|
||||
}
|
||||
|
||||
// 同时添加 company 和 store 类型
|
||||
UserDataScope::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'scope_type' => 'company',
|
||||
'scope_id' => $store->company_id,
|
||||
]);
|
||||
|
||||
// 找一个不属于该 company 的 store
|
||||
$other_store = Store::query()
|
||||
->where('company_id', '!=', $store->company_id)
|
||||
->first();
|
||||
if ($other_store) {
|
||||
UserDataScope::query()->create([
|
||||
'user_id' => $user->id,
|
||||
'scope_type' => 'store',
|
||||
'scope_id' => $other_store->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$bitmap = $this->service->buildForUser($user->id);
|
||||
$this->assertNotEmpty($bitmap);
|
||||
// company 下的 store 在 bitmap 中
|
||||
$this->assertTrue($this->service->has($bitmap, $store->id));
|
||||
// 额外的 store 也在
|
||||
if ($other_store) {
|
||||
$this->assertTrue($this->service->has($bitmap, $other_store->id));
|
||||
}
|
||||
} finally {
|
||||
Db::rollBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- buildForDeveloper ---
|
||||
|
||||
public function test_build_for_developer_returns_platform_stores(): void
|
||||
{
|
||||
$this->runInCoroutine(function (): void {
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
$user = User::query()->first();
|
||||
|
||||
// 查找有 store 的 platform
|
||||
$store = Store::query()->first();
|
||||
if (!$store) {
|
||||
$this->markTestSkipped('需要至少 1 个 store 记录');
|
||||
}
|
||||
|
||||
// 将 platform 绑定到用户
|
||||
Platform::query()
|
||||
->where('id', $store->platform_id)
|
||||
->update(['developer_id' => $user->id]);
|
||||
|
||||
$bitmap = $this->service->buildForDeveloper($user->id);
|
||||
$this->assertNotEmpty($bitmap);
|
||||
|
||||
$platform_stores = Store::query()
|
||||
->where('platform_id', $store->platform_id)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
foreach ($platform_stores as $sid) {
|
||||
$this->assertTrue($this->service->has($bitmap, $sid));
|
||||
}
|
||||
} finally {
|
||||
Db::rollBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_build_for_developer_no_platforms_returns_empty(): void
|
||||
{
|
||||
$this->runInCoroutine(function (): void {
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
// 创建一个不维护任何平台的用户
|
||||
$user = User::query()->create([
|
||||
'username' => 'dev_no_platform_' . uniqid(),
|
||||
'email' => 'devnp_' . uniqid() . '@test.com',
|
||||
'password' => 'password',
|
||||
'status' => 1,
|
||||
]);
|
||||
|
||||
$bitmap = $this->service->buildForDeveloper($user->id);
|
||||
$this->assertSame('', $bitmap);
|
||||
} finally {
|
||||
Db::rollBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user