22// for details. All rights reserved. Use of this source code is governed by a
33// BSD-style license that can be found in the LICENSE file.
44
5+ import 'dart:async' ;
56import 'dart:io' as io;
67import 'dart:io' ;
78import 'dart:isolate' ;
89
10+ import 'package:async/async.dart' ;
911import 'package:test/test.dart' ;
1012import 'package:test_descriptor/test_descriptor.dart' as d;
1113import 'package:watcher/src/utils.dart' ;
14+ import 'package:watcher/watcher.dart' ;
1215
1316import '../utils.dart' ;
1417
@@ -34,6 +37,79 @@ void _fileTests({required bool isNative}) {
3437 }
3538 });
3639
40+ // ResubscribableWatcher wraps all the directory watchers to add handling of
41+ // multiple subscribers. The underlying watcher is created when there is at
42+ // least one subscriber and closed when there are zero subscribers. So,
43+ // exercise that behavior in various ways.
44+ test ('ResubscribableWatcher handles multiple subscriptions ' , () async {
45+ final watcher = createWatcher ();
46+
47+ // One subscription then close it.
48+ final queue1 = StreamQueue (watcher.events);
49+ final event1 = queue1.next;
50+ await watcher.ready;
51+ writeFile ('a.txt' );
52+ expect (await event1, isAddEvent ('a.txt' ));
53+ await queue1.cancel (immediate: true );
54+
55+ // Open before "ready", cancel before event.
56+ final queue2a = StreamQueue (watcher.events);
57+ // Open before "ready", cancel after one event.
58+ final queue2b = StreamQueue (watcher.events);
59+ // Open before "ready", cancel after two events.
60+ final queue2c = StreamQueue (watcher.events);
61+
62+ final queue2aHasNext = queue2a.hasNext;
63+ unawaited (queue2a.cancel (immediate: true ));
64+ expect (await queue2aHasNext, false );
65+
66+ await watcher.ready;
67+
68+ // Open after "ready", cancel before event.
69+ final queue2d = StreamQueue (watcher.events);
70+
71+ // Open after "ready", cancel after one event.
72+ final queue2e = StreamQueue (watcher.events);
73+
74+ // Open after "ready", cancel after two events.
75+ final queue2f = StreamQueue (watcher.events);
76+
77+ unawaited (queue2d.cancel (immediate: true ));
78+
79+ writeFile ('b.txt' );
80+
81+ expect (await queue2b.next, isAddEvent ('b.txt' ));
82+ expect (await queue2c.next, isAddEvent ('b.txt' ));
83+ expect (await queue2e.next, isAddEvent ('b.txt' ));
84+ expect (await queue2f.next, isAddEvent ('b.txt' ));
85+ final queue2bHasNext = queue2b.hasNext;
86+ await queue2b.cancel (immediate: true );
87+ expect (await queue2bHasNext, false );
88+ final queue2eHasNext = queue2e.hasNext;
89+ await queue2e.cancel (immediate: true );
90+ expect (await queue2eHasNext, false );
91+
92+ // Remaining subscriptions still get events.
93+ writeFile ('c.txt' );
94+ expect (await queue2c.next, isAddEvent ('c.txt' ));
95+ expect (await queue2f.next, isAddEvent ('c.txt' ));
96+ final queue2cHasNext = queue2c.hasNext;
97+ await queue2c.cancel (immediate: true );
98+ expect (await queue2cHasNext, false );
99+ final queue2fHasNext = queue2f.hasNext;
100+ await queue2f.cancel (immediate: true );
101+ expect (await queue2fHasNext, false );
102+
103+ // Repeat the first simple test: one subscription then close it.
104+ final queue3 = StreamQueue (watcher.events);
105+ await watcher.ready;
106+ writeFile ('d.txt' );
107+ expect (await queue3.next, isAddEvent ('d.txt' ));
108+ final queue3HasNext = queue3.hasNext;
109+ await queue3.cancel (immediate: true );
110+ expect (await queue3HasNext, false );
111+ });
112+
37113 test ('does not notify for files that already exist when started' , () async {
38114 // Make some pre-existing files.
39115 writeFile ('a.txt' );
0 commit comments