Seed five worker robot agents (TR-01 to TR-05) with Portuguese system prompts and active status. Extend the 3D humanoid renderer with metallic materials, glowing visor, antenna beacon, and chest status light for the worker_robot type. Add feature tests covering payload serialization and city bounds validation.
89 lines
2.9 KiB
PHP
89 lines
2.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\AiAgent;
|
|
use App\Models\Character;
|
|
use App\Models\User;
|
|
use Database\Seeders\CityWorldSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Humanoid worker robots: seeded as walkable agents with allow-listed
|
|
* models and in-city positions so the viewer spawns them on routes.
|
|
*/
|
|
class WorkerRobotTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
/**
|
|
* Boot world fixtures.
|
|
*/
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->seed(CityWorldSeeder::class);
|
|
$user = User::factory()->create(['status' => User::STATUS_ACTIVE, 'is_active' => true]);
|
|
Character::ensureForUser($user);
|
|
$this->actingAs($user);
|
|
}
|
|
|
|
/**
|
|
* The payload carries the five worker robots; their AI personas
|
|
* (model/prompt) live only in the database — never in the public
|
|
* world payload.
|
|
*/
|
|
public function test_payload_contains_worker_robots(): void
|
|
{
|
|
$payload = $this->getJson('/city/data')->assertOk()->json();
|
|
|
|
$robots = array_values(array_filter(
|
|
$payload['agents'],
|
|
static fn (array $a): bool => $a['type'] === 'worker_robot'
|
|
));
|
|
|
|
$this->assertCount(5, $robots);
|
|
$this->assertSame(
|
|
['Robô TR-01', 'Robô TR-02', 'Robô TR-03', 'Robô TR-04', 'Robô TR-05'],
|
|
array_column($robots, 'name')
|
|
);
|
|
foreach ($robots as $robot) {
|
|
$this->assertSame('active', $robot['status']);
|
|
}
|
|
|
|
// Personas are stored server-side only.
|
|
$this->assertArrayNotHasKey('model', $robots[0]);
|
|
$this->assertArrayNotHasKey('system_prompt', $robots[0]);
|
|
|
|
foreach (AiAgent::where('type', 'worker_robot')->get() as $agent) {
|
|
$this->assertContains($agent->model, config('ai.allowed_models'));
|
|
$this->assertNotEmpty($agent->system_prompt);
|
|
$this->assertStringContainsString('robô', $agent->system_prompt);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Robot spawn points sit inside the city bounds (they seed the DB
|
|
* row; the viewer re-places them on walking routes).
|
|
*/
|
|
public function test_robot_positions_stay_inside_city_bounds(): void
|
|
{
|
|
$payload = $this->getJson('/city/data')->assertOk()->json();
|
|
$bounds = $payload['city']['bounds'];
|
|
|
|
$robots = array_values(array_filter(
|
|
$payload['agents'],
|
|
static fn (array $a): bool => $a['type'] === 'worker_robot'
|
|
));
|
|
$this->assertNotEmpty($robots);
|
|
|
|
foreach ($robots as $robot) {
|
|
$this->assertGreaterThanOrEqual($bounds['min_x'], $robot['position'][0]);
|
|
$this->assertLessThanOrEqual($bounds['max_x'], $robot['position'][0]);
|
|
$this->assertGreaterThanOrEqual($bounds['min_z'], $robot['position'][2]);
|
|
$this->assertLessThanOrEqual($bounds['max_z'], $robot['position'][2]);
|
|
}
|
|
}
|
|
}
|