import 'package:farolero/modelos/sala_multijugador.dart'; import 'package:farolero/modelos/usuario.dart'; import 'package:flutter_test/flutter_test.dart'; EstadoSalaMultijugador _salaConCliente() { final sala = EstadoSalaMultijugador.crear( roomId: 'r1', nombreSala: 'Sala', hostClientId: 'host', hostNombre: 'Ana', ); sala.registrarCliente( const ClienteSala( clientId: 'dev-beto', endpointId: 'ep-1', nombre: 'Beto', ), ); sala.usuarios['u-beto'] = Usuario( id: 'u-beto', nombre: 'Beto', creadoPorClienteId: 'dev-beto', clienteIdSeleccionado: 'dev-beto', ); return sala; } void main() { group('Reconexión de un cliente', () { test('el mismo clientId con endpoint nuevo no crea un cliente duplicado', () { final sala = _salaConCliente(); sala.registrarCliente( const ClienteSala( clientId: 'dev-beto', endpointId: 'ep-2', nombre: 'Beto', ), ); expect(sala.clientes.length, 2, reason: 'host + Beto, sin duplicados'); expect(sala.clientes['dev-beto']!.endpointId, 'ep-2'); expect(sala.clientes['dev-beto']!.conectado, isTrue); }); test('esReconexion distingue a quien vuelve de quien llega nuevo', () { final sala = _salaConCliente(); expect(sala.esReconexion('dev-beto'), isTrue); expect(sala.esReconexion('dev-cris'), isFalse); }); test('en partida, desconectarse no libera a sus jugadores', () { final sala = _salaConCliente(); sala.fase = FaseSalaMultijugador.enPartida; sala.desconectarCliente('dev-beto'); expect(sala.usuarios['u-beto']!.clienteIdSeleccionado, 'dev-beto'); expect(sala.clientes['dev-beto']!.conectado, isFalse); }); test('en lobby, desconectarse sí libera a sus jugadores', () { final sala = _salaConCliente(); sala.desconectarCliente('dev-beto'); expect(sala.usuarios['u-beto']!.estaDisponible, isTrue); }); }); group('Absorción por el host y devolución', () { test('el host absorbe y queda constancia de quién era el dueño', () { final sala = _salaConCliente(); sala.fase = FaseSalaMultijugador.enPartida; sala.desconectarCliente('dev-beto'); final reasignados = sala.reasignarUsuariosDeCliente( clientIdOrigen: 'dev-beto', clientIdDestino: 'host', ); expect(reasignados, 1); expect(sala.usuarios['u-beto']!.clienteIdSeleccionado, 'host'); expect(sala.usuarios['u-beto']!.absorbidoDe, 'dev-beto'); expect(sala.usuariosAbsorbidosDe('dev-beto').single.id, 'u-beto'); }); test('al volver el móvil recupera a sus jugadores', () { final sala = _salaConCliente(); sala.fase = FaseSalaMultijugador.enPartida; sala.desconectarCliente('dev-beto'); sala.reasignarUsuariosDeCliente( clientIdOrigen: 'dev-beto', clientIdDestino: 'host', ); sala.registrarCliente( const ClienteSala( clientId: 'dev-beto', endpointId: 'ep-2', nombre: 'Beto', ), ); final devueltos = sala.devolverUsuariosAbsorbidos('dev-beto'); expect(devueltos, 1); expect(sala.usuarios['u-beto']!.clienteIdSeleccionado, 'dev-beto'); expect(sala.usuarios['u-beto']!.absorbidoDe, isNull); expect(sala.usuariosPorCliente('host'), isEmpty); }); test('una doble absorción no pierde al dueño original', () { final sala = _salaConCliente(); sala.fase = FaseSalaMultijugador.enPartida; sala.reasignarUsuariosDeCliente( clientIdOrigen: 'dev-beto', clientIdDestino: 'host', ); // El host vuelve a pasar por el mismo camino: no debe reescribir el // origen a 'host' y dejar al usuario huérfano. sala.reasignarUsuariosDeCliente( clientIdOrigen: 'host', clientIdDestino: 'host', ); expect(sala.usuarios['u-beto']!.absorbidoDe, 'dev-beto'); }); test('no se devuelve nada a un cliente que no está en la sala', () { final sala = _salaConCliente(); sala.reasignarUsuariosDeCliente( clientIdOrigen: 'dev-beto', clientIdDestino: 'host', ); expect(sala.devolverUsuariosAbsorbidos('dev-fantasma'), 0); }); }); group('Serialización', () { test('absorbidoDe sobrevive al viaje JSON', () { final sala = _salaConCliente(); sala.fase = FaseSalaMultijugador.enPartida; sala.reasignarUsuariosDeCliente( clientIdOrigen: 'dev-beto', clientIdDestino: 'host', ); final reparsed = EstadoSalaMultijugador.fromJson(sala.toJson()); expect(reparsed.usuarios['u-beto']!.absorbidoDe, 'dev-beto'); expect(reparsed.clientes['dev-beto']!.endpointId, 'ep-1'); }); }); }