- Adds Character model with survival needs (hunger, thirst, energy) and state machine - Implements city:tick world ticker for offline progression every minute - Adds city territory expansion and building construction system - Introduces job economy, inventory, and transaction audit trail - Adds social graph (friends, marriage, children) and character chat - Implements admin approval workflow for new registrations - Adds hospital admission system for traffic accidents - Includes comprehensive feature tests and world seeders
132 lines
4.2 KiB
PHP
Executable File
132 lines
4.2 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Character;
|
|
use App\Models\CharacterMessage;
|
|
use App\Models\Relationship;
|
|
use App\Models\User;
|
|
use Database\Seeders\CityWorldSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Social graph and character chat coverage.
|
|
*/
|
|
class CitySocialTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
/**
|
|
* Seed world fixtures.
|
|
*/
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->seed(CityWorldSeeder::class);
|
|
}
|
|
|
|
/**
|
|
* Friendship request flows from pending to accepted.
|
|
*/
|
|
public function test_friend_request_and_accept(): void
|
|
{
|
|
$a = Character::factory()->create();
|
|
$b = Character::factory()->create();
|
|
$userA = User::factory()->create(['status' => User::STATUS_ACTIVE, 'is_active' => true]);
|
|
$a->user_id = $userA->id;
|
|
$a->save();
|
|
|
|
$this->actingAs($userA)
|
|
->postJson('/city/social/friend', ['character_id' => $b->id])
|
|
->assertOk();
|
|
|
|
$rel = Relationship::where('type', Relationship::TYPE_FRIEND)
|
|
->where('character_a_id', $a->id)
|
|
->where('character_b_id', $b->id)
|
|
->first();
|
|
$this->assertNotNull($rel);
|
|
$this->assertSame(Relationship::STATUS_PENDING, $rel->status);
|
|
|
|
$userB = User::factory()->create(['status' => User::STATUS_ACTIVE, 'is_active' => true]);
|
|
$b->user_id = $userB->id;
|
|
$b->save();
|
|
|
|
$this->actingAs($userB)
|
|
->postJson('/city/social/accept-friend', ['relationship_id' => $rel->id])
|
|
->assertOk();
|
|
|
|
$this->assertSame(Relationship::STATUS_ACCEPTED, $rel->fresh()->status);
|
|
}
|
|
|
|
/**
|
|
* Marriage requires an accepted friendship.
|
|
*/
|
|
public function test_marry_requires_friendship(): void
|
|
{
|
|
$userA = User::factory()->create(['status' => User::STATUS_ACTIVE, 'is_active' => true]);
|
|
$a = Character::ensureForUser($userA);
|
|
$b = Character::factory()->create(['city_id' => $a->city_id]);
|
|
|
|
$this->actingAs($userA)
|
|
->postJson('/city/social/marry', ['character_id' => $b->id])
|
|
->assertStatus(422);
|
|
}
|
|
|
|
/**
|
|
* Spouses can have an NPC child linked to both parents.
|
|
*/
|
|
public function test_child_creates_npc_character(): void
|
|
{
|
|
$userA = User::factory()->create(['status' => User::STATUS_ACTIVE, 'is_active' => true]);
|
|
$a = Character::ensureForUser($userA);
|
|
$b = Character::factory()->create(['city_id' => $a->city_id, 'name' => 'Parceiro']);
|
|
|
|
Relationship::create([
|
|
'character_a_id' => $a->id,
|
|
'character_b_id' => $b->id,
|
|
'type' => Relationship::TYPE_FRIEND,
|
|
'status' => Relationship::STATUS_ACCEPTED,
|
|
]);
|
|
Relationship::create([
|
|
'character_a_id' => $a->id,
|
|
'character_b_id' => $b->id,
|
|
'type' => Relationship::TYPE_SPOUSE,
|
|
'status' => Relationship::STATUS_ACCEPTED,
|
|
]);
|
|
|
|
$before = Character::count();
|
|
$this->actingAs($userA)
|
|
->postJson('/city/social/child', ['character_id' => $b->id])
|
|
->assertOk();
|
|
$this->assertSame($before + 1, Character::count());
|
|
|
|
$child = Character::orderByDesc('id')->first();
|
|
$this->assertNull($child->user_id);
|
|
$this->assertSame(2, Relationship::where('type', Relationship::TYPE_PARENT_CHILD)
|
|
->where('character_a_id', $child->id)->count());
|
|
}
|
|
|
|
/**
|
|
* Messages persist between characters.
|
|
*/
|
|
public function test_character_chat_persists(): void
|
|
{
|
|
$userA = User::factory()->create(['status' => User::STATUS_ACTIVE, 'is_active' => true]);
|
|
$a = Character::ensureForUser($userA);
|
|
$b = Character::factory()->create(['city_id' => $a->city_id]);
|
|
|
|
$this->actingAs($userA)
|
|
->postJson("/city/messages/{$b->id}", ['body' => 'Olá vizinho!'])
|
|
->assertOk();
|
|
|
|
$this->assertSame(1, CharacterMessage::count());
|
|
|
|
$this->actingAs($userA)
|
|
->getJson("/city/messages/{$b->id}")
|
|
->assertOk()
|
|
->assertJsonPath('me', $a->id)
|
|
->assertJsonPath('messages.0.body', 'Olá vizinho!');
|
|
}
|
|
}
|