delete(); File::deleteDirectory(storage_path('app/audit')); }); it('displays security audit logs in console table format', function (): void { // GIVEN /** @var \Tests\TestCase $this */ $clientId = Uuid::uuid7()->toString(); $clientIdentifier = 'arcadia_id_' . str_repeat('g', 32); $logId = Uuid::uuid7(new \DateTimeImmutable('2026-08-20 10:00:00 UTC')); ClientAuditLog::query()->create([ 'id' => $logId->toString(), 'client_id' => $clientId, 'client_identifier' => $clientIdentifier, 'event_type' => 'client_secret_generated', 'details' => null, ]); // WHEN $this->artisan('arcadia:security:audit-logs', [ '--since' => '2026-08-01', '--to' => '2026-08-21 23:59:59', ]) // THEN ->expectsTable( ['Date (UTC)', 'Event', 'Client Identifier', 'Client ID (UUID)', 'Details'], [ [ '2026-08-20 10:00:00', 'client_secret_generated', $clientIdentifier, $clientId, '', ], ] ) ->expectsOutput('Total: 1 event(s) found.') ->assertSuccessful(); }); it('displays notice when no logs are found in the specified range', function (): void { // GIVEN /** @var \Tests\TestCase $this */ // WHEN $this->artisan('arcadia:security:audit-logs', [ '--since' => '2026-08-01', '--to' => '2026-08-02', ]) // THEN ->expectsOutputToContain('No security audit logs found') ->assertSuccessful(); }); it('exports logs to CSV in storage directory when --csv is specified', function (): void { // GIVEN /** @var \Tests\TestCase $this */ $clientId = Uuid::uuid7()->toString(); $clientIdentifier = 'arcadia_id_' . str_repeat('e', 32); $logId = Uuid::uuid7(new \DateTimeImmutable('2026-08-18 15:30:00 UTC')); ClientAuditLog::query()->create([ 'id' => $logId->toString(), 'client_id' => $clientId, 'client_identifier' => $clientIdentifier, 'event_type' => 'client_status_toggled', 'details' => ['is_active' => 'false'], ]); // WHEN $this->artisan('arcadia:security:audit-logs', [ '--since' => '2026-08-01', '--csv' => true, ]) // THEN ->expectsOutputToContain('Exported 1 security audit log(s) to') ->assertSuccessful(); $files = File::files(storage_path('app/audit')); expect($files)->toHaveCount(1); $csvContent = File::get($files[0]->getPathname()); expect($csvContent)->toContain($clientIdentifier) ->and($csvContent)->toContain('client_status_toggled') ->and($csvContent)->toContain('is_active'); }); it('fails when an invalid date format is provided for --since', function (): void { // GIVEN & WHEN & THEN /** @var \Tests\TestCase $this */ $this->artisan('arcadia:security:audit-logs', [ '--since' => 'invalid-date-string', ]) ->expectsOutputToContain("Invalid date format for --since: 'invalid-date-string'.") ->assertFailed(); }); });