fake_async icon indicating copy to clipboard operation
fake_async copied to clipboard

StreamSubscription.cancel hangs up

Open mercsst opened this issue 1 year ago • 0 comments

I have a test that passes normally if run without FakeAsync, but freezes mid execution under FakeAsync. After some time debugging, it looks like the problem is somehow related to StreamSubscription's cancel method.

Here is a sample to demonstrate:

import 'dart:async';

import 'package:fake_async/fake_async.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';

class ServiceUnderTest {
  ServiceUnderTest(this.stream);

  Stream<bool> stream;
  StreamSubscription<dynamic>? _subscription;

  Future<void> start() async {
    _subscription = stream.listen((event) {
      debugPrintSynchronously('event: $event');
    });
  }

  Future<void> stop() async {
    debugPrintSynchronously('stop begun');
    await _subscription?.cancel();
    _subscription = null;
    debugPrintSynchronously('stop 1');
    await _subscription?.cancel();
    debugPrintSynchronously('stop finished');
  }
}

void main() {
  late ServiceUnderTest serviceUnderTest;

  setUp(() {
    final controller = StreamController<bool>();
    controller.add(true);

    serviceUnderTest = ServiceUnderTest(controller.stream);
  });

  test('No fakeAsync - Passes normally', () async {
    await serviceUnderTest.start();
    await expectLater(serviceUnderTest.stop(), completes);
  });

  test('With fakeAsync - Hangs up', () async {
    FakeAsync().run((async) {
      serviceUnderTest.start();
      async.flushMicrotasks();
      async.elapse(const Duration(seconds: 2));

      expectLater(serviceUnderTest.stop(), completes);
      async.flushMicrotasks();
      async.elapse(const Duration(seconds: 2));
    });
  });
}

First test would pass with no problems, but second one will output:

event: true
stop begun
stop 1

and hang up.

Is this an expected behaviour ? If so, how could i remedy it.

mercsst avatar Feb 13 '24 22:02 mercsst