// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. 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:test/test.dart';

// Test that stream listener callbacks all happen in the zone where the
// listen occurred.

void main() {
  StreamController controller;
  controller = StreamController<void>();
  testStream('singlesub-async', controller, controller.stream);
  controller = StreamController.broadcast();
  testStream('broadcast-async', controller, controller.stream);
  controller = StreamController<void>();
  testStream(
      'asbroadcast-async', controller, controller.stream.asBroadcastStream());

  controller = StreamController(sync: true);
  testStream('singlesub-sync', controller, controller.stream);
  controller = StreamController.broadcast(sync: true);
  testStream('broadcast-sync', controller, controller.stream);
  controller = StreamController(sync: true);
  testStream(
      'asbroadcast-sync', controller, controller.stream.asBroadcastStream());
}

void testStream(String name, StreamController controller, Stream stream) {
  test(name, () {
    var outer = Zone.current;
    runZoned(() {
      var newZone1 = Zone.current;
      late StreamSubscription sub;
      sub = stream.listen(expectAsync1((v) {
        expect(v, 42);
        expect(Zone.current, newZone1);
        outer.run(() {
          sub.onData(expectAsync1((v) {
            expect(v, 37);
            expect(Zone.current, newZone1);
            runZoned(() {
              sub.onData(expectAsync1((v) {
                expect(v, 87);
                expect(Zone.current, newZone1);
              }));
            });
            if (controller is SynchronousStreamController) {
              scheduleMicrotask(() => controller.add(87));
            } else {
              controller.add(87);
            }
          }));
        });
        if (controller is SynchronousStreamController) {
          scheduleMicrotask(() => controller.add(37));
        } else {
          controller.add(37);
        }
      }));
    });
    controller.add(42);
  });
}
