// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:async'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/commands/daemon.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; void main() { testWithoutContext('binds on ipv4 normally', () async { final FakeServerSocket socket = FakeServerSocket(); final BufferLogger logger = BufferLogger.test(); int bindCalledTimes = 0; final List bindAddresses = []; final List bindPorts = []; final DaemonServer server = DaemonServer( port: 123, logger: logger, bind: (Object? address, int port) async { bindCalledTimes++; bindAddresses.add(address); bindPorts.add(port); return socket; }, ); await server.run(); expect(bindCalledTimes, 1); expect(bindAddresses, [InternetAddress.loopbackIPv4]); expect(bindPorts, [123]); }); testWithoutContext('binds on ipv6 if ipv4 failed normally', () async { final FakeServerSocket socket = FakeServerSocket(); final BufferLogger logger = BufferLogger.test(); int bindCalledTimes = 0; final List bindAddresses = []; final List bindPorts = []; final DaemonServer server = DaemonServer( port: 123, logger: logger, bind: (Object? address, int port) async { bindCalledTimes++; bindAddresses.add(address); bindPorts.add(port); if (address == InternetAddress.loopbackIPv4) { throw const SocketException('fail'); } return socket; }, ); await server.run(); expect(bindCalledTimes, 2); expect(bindAddresses, [InternetAddress.loopbackIPv4, InternetAddress.loopbackIPv6]); expect(bindPorts, [123, 123]); }); } class FakeServerSocket extends Fake implements ServerSocket { FakeServerSocket(); @override int get port => 1; bool closeCalled = false; final StreamController controller = StreamController(); @override StreamSubscription listen( void Function(Socket event)? onData, { Function? onError, void Function()? onDone, bool? cancelOnError, }) { // Close the controller immediately for testing purpose. scheduleMicrotask(() { controller.close(); }); return controller.stream.listen( onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError, ); } @override Future close() async { closeCalled = true; return this; } }