100], ['value_json' => 200], '203.0.113.10', 'PHPUnit', ); expect($row)->toBeInstanceOf(AuditLog::class) ->operator_type->toBe(AuditLogger::OPERATOR_ADMIN) ->operator_id->toBe(42) ->module_code->toBe('settings') ->action_code->toBe('update') ->target_type->toBe('lottery_setting') ->target_id->toBe('deposit_min') ->before_json->toBe(['value_json' => 100]) ->after_json->toBe(['value_json' => 200]) ->ip->toBe('203.0.113.10') ->user_agent->toBe('PHPUnit'); expect(AuditLog::query()->count())->toBe(1); }); test('audit logger truncates user agent to 255', function (): void { $ua = str_repeat('a', 300); $row = AuditLogger::record(AuditLogger::OPERATOR_SYSTEM, 0, 'job', 'run', ip: null, userAgent: $ua); expect(strlen((string) $row->user_agent))->toBe(255); }); test('audit logger record from request fills ip', function (): void { $request = Request::create('/fake', 'POST', server: [ 'REMOTE_ADDR' => '198.51.100.2', 'HTTP_USER_AGENT' => 'TestAgent', ]); $row = AuditLogger::recordFromRequest( $request, AuditLogger::OPERATOR_PLAYER, 7, 'wallet', 'transfer', null, null, ['x' => 1], ['x' => 2], ); expect($row) ->ip->toContain('198.51.100.2') ->user_agent->toBe('TestAgent'); expect($request->attributes->get(RecordAdminApiAudit::ATTRIBUTE_AUDIT_RECORDED))->toBeTrue(); }); test('record for system uses operator zero', function (): void { AuditLogger::recordForSystem('reconcile', 'start', targetId: '2026-01'); /** @var AuditLog|null $row */ $row = AuditLog::query()->latest('id')->first(); expect($row)->not->toBeNull() ->operator_type->toBe(AuditLogger::OPERATOR_SYSTEM) ->operator_id->toBe(0); });