176 lines
4.9 KiB
PHP
176 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\GameConfig;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Redis;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* 类功能:覆盖钓鱼小游戏抛竿、收竿和令牌校验流程。
|
|
*/
|
|
class FishingControllerTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
/**
|
|
* 初始化钓鱼配置并清理 Redis 状态。
|
|
*/
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
Redis::flushall();
|
|
|
|
GameConfig::updateOrCreate(
|
|
['game_key' => 'fishing'],
|
|
[
|
|
'name' => 'Fishing',
|
|
'icon' => 'fish',
|
|
'description' => 'Fishing Game',
|
|
'enabled' => true,
|
|
'params' => [
|
|
'fishing_cost' => 5,
|
|
'fishing_cooldown' => 300,
|
|
],
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 方法功能:验证用户金币足够时可以正常抛竿并扣除费用。
|
|
*/
|
|
public function test_can_cast_rod(): void
|
|
{
|
|
/** @var \App\Models\User $user */
|
|
$user = User::factory()->create(['jjb' => 10]);
|
|
|
|
$response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1]));
|
|
|
|
$response->assertStatus(200);
|
|
$response->assertJson([
|
|
'status' => 'success',
|
|
'cost' => 5,
|
|
]);
|
|
|
|
$this->assertEquals(5, $user->fresh()->jjb);
|
|
}
|
|
|
|
/**
|
|
* 方法功能:验证冷却期间不能重复抛竿。
|
|
*/
|
|
public function test_cannot_cast_when_on_cooldown(): void
|
|
{
|
|
/** @var \App\Models\User $user */
|
|
$user = User::factory()->create(['jjb' => 10]);
|
|
Redis::setex("fishing:cd:{$user->id}", 100, time());
|
|
|
|
$response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1]));
|
|
|
|
$response->assertStatus(429);
|
|
$response->assertJson([
|
|
'status' => 'error',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 方法功能:验证金币不足时不能抛竿。
|
|
*/
|
|
public function test_cannot_cast_without_enough_gold(): void
|
|
{
|
|
/** @var \App\Models\User $user */
|
|
$user = User::factory()->create(['jjb' => 2]);
|
|
|
|
$response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1]));
|
|
|
|
$response->assertStatus(422);
|
|
$response->assertJson([
|
|
'status' => 'error',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 方法功能:验证等待完成后携带正确令牌可以成功收竿。
|
|
*/
|
|
public function test_can_reel_after_waiting(): void
|
|
{
|
|
/** @var \App\Models\User $user */
|
|
$user = User::factory()->create(['jjb' => 10]);
|
|
|
|
$token = 'test-token';
|
|
|
|
Redis::set("fishing:token:{$user->id}", json_encode([
|
|
'token' => $token,
|
|
'cast_at' => time() - 1, // Simulate past
|
|
'wait_time' => 0,
|
|
]));
|
|
|
|
$response = $this->actingAs($user)->postJson(route('fishing.reel', ['id' => 1]), [
|
|
'token' => $token,
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$response->assertJson([
|
|
'status' => 'success',
|
|
]);
|
|
|
|
// Cooldown should be set
|
|
$this->assertTrue((bool) Redis::exists("fishing:cd:{$user->id}"));
|
|
}
|
|
|
|
/**
|
|
* 方法功能:验证错误令牌不能收竿。
|
|
*/
|
|
public function test_cannot_reel_with_invalid_token(): void
|
|
{
|
|
/** @var \App\Models\User $user */
|
|
$user = User::factory()->create(['jjb' => 10]);
|
|
|
|
Redis::set("fishing:token:{$user->id}", json_encode([
|
|
'token' => 'valid-token',
|
|
'cast_at' => time(),
|
|
'wait_time' => 0,
|
|
]));
|
|
|
|
$response = $this->actingAs($user)->postJson(route('fishing.reel', ['id' => 1]), [
|
|
'token' => 'invalid-token',
|
|
]);
|
|
|
|
$response->assertStatus(422);
|
|
$response->assertJson([
|
|
'status' => 'error',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 方法功能:验证已有未收竿令牌时再次抛竿会恢复原会话且不会重复扣金币。
|
|
*/
|
|
public function test_cast_restores_active_token_without_charging_again(): void
|
|
{
|
|
/** @var \App\Models\User $user */
|
|
$user = User::factory()->create(['jjb' => 10]);
|
|
$tokenKey = "fishing:token:{$user->id}";
|
|
$payload = json_encode([
|
|
'token' => 'active-token',
|
|
'cast_at' => time(),
|
|
'wait_time' => 10,
|
|
]);
|
|
|
|
Redis::setex($tokenKey, 20, $payload);
|
|
|
|
$response = $this->actingAs($user)->postJson(route('fishing.cast', ['id' => 1]));
|
|
|
|
$response->assertStatus(200);
|
|
$response->assertJson([
|
|
'status' => 'success',
|
|
'token' => 'active-token',
|
|
'cost' => 0,
|
|
'restored' => true,
|
|
]);
|
|
|
|
$this->assertSame(10, $user->fresh()->jjb);
|
|
$this->assertSame($payload, Redis::get($tokenKey));
|
|
}
|
|
}
|