import 'package:flutter_test/flutter_test.dart'; import 'package:nomadcode_app/src/integrations/proto_socket/proto_socket_endpoint_config.dart'; import 'package:nomadcode_app/src/integrations/proto_socket/proto_socket_lifecycle.dart'; class _FakeConnector implements ProtoSocketConnector { int connectCalls = 0; int disconnectCalls = 0; Object? throwOnConnect; @override Future connect(ProtoSocketEndpointConfig config) async { connectCalls += 1; final err = throwOnConnect; if (err != null) throw err; } @override Future disconnect() async { disconnectCalls += 1; } } void main() { const config = ProtoSocketEndpointConfig( host: 'core.example.com', port: 443, secure: true, ); test('happy path emits connecting -> connected -> disconnected', () async { final fake = _FakeConnector(); final lifecycle = ProtoSocketLifecycle(connector: fake); final states = []; final sub = lifecycle.stateStream.listen(states.add); expect(lifecycle.state, ProtoSocketConnectionState.disconnected); await lifecycle.connect(config); expect(lifecycle.state, ProtoSocketConnectionState.connected); expect(fake.connectCalls, equals(1)); await lifecycle.disconnect(); expect(lifecycle.state, ProtoSocketConnectionState.disconnected); expect(fake.disconnectCalls, equals(1)); await Future.delayed(Duration.zero); await sub.cancel(); await lifecycle.dispose(); expect(states, [ ProtoSocketConnectionState.connecting, ProtoSocketConnectionState.connected, ProtoSocketConnectionState.disconnected, ]); }); test('connect failure transitions to failed and records error', () async { final fake = _FakeConnector()..throwOnConnect = StateError('boom'); final lifecycle = ProtoSocketLifecycle(connector: fake); await expectLater(lifecycle.connect(config), throwsA(isA())); expect(lifecycle.state, ProtoSocketConnectionState.failed); expect(lifecycle.lastError, isA()); await lifecycle.dispose(); }); test('connect is a no-op when already connecting or connected', () async { final fake = _FakeConnector(); final lifecycle = ProtoSocketLifecycle(connector: fake); await lifecycle.connect(config); await lifecycle.connect(config); expect(fake.connectCalls, equals(1)); await lifecycle.dispose(); }); test('disconnect from disconnected state is a no-op', () async { final fake = _FakeConnector(); final lifecycle = ProtoSocketLifecycle(connector: fake); await lifecycle.disconnect(); expect(fake.disconnectCalls, equals(0)); expect(lifecycle.state, ProtoSocketConnectionState.disconnected); await lifecycle.dispose(); }); }