11// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
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.
4+ // ignore_for_file: unreachable_from_main
45
56import 'dart:io' ;
67
78import 'package:path/path.dart' as p;
8- import 'package:test/test.dart' ;
9+ import 'package:test/test.dart' as package_test;
10+ import 'package:watcher/watcher.dart' ;
911
10- import '../utils.dart' ;
12+ import '../utils.dart' as utils ;
1113import 'client_simulator.dart' ;
1214import 'file_changer.dart' ;
1315
@@ -16,56 +18,101 @@ import 'file_changer.dart';
1618///
1719/// The test passes if the [ClientSimulator] tracking matches what's actually on
1820/// disk.
21+ void endToEndTests () {
22+ package_test.test ('end to end test' ,
23+ timeout: const package_test.Timeout (Duration (minutes: 5 )), () async {
24+ await _runTest ();
25+ });
26+ }
27+
28+ /// Runs the test.
1929///
20- /// Fails on Linux due to https://github.com/dart-lang/tools/issues/2228.
30+ /// To run without `package:test` , pass [addTearDown] , [createWatcher] , [fail]
31+ /// and [printOnFailure] replacements.
2132///
22- /// Fails sometimes on Windows due to
23- /// https://github.com/dart-lang/tools/issues/2234.
24- void endToEndTests ({required bool isNative}) {
25- test ('end to end test' , timeout: const Timeout (Duration (minutes: 5 )),
26- () async {
27- final temp = Directory .systemTemp.createTempSync ();
28- addTearDown (() => temp.deleteSync (recursive: true ));
33+ /// To run until failure, set [endlessMode] to `true` .
34+ Future <void > _runTest ({
35+ void Function (void Function ())? addTearDown,
36+ Watcher Function ({required String path})? createWatcher,
37+ void Function (String )? fail,
38+ void Function (String )? printOnFailure,
39+ bool endlessMode = false ,
40+ }) async {
41+ addTearDown ?? = package_test.addTearDown;
42+ createWatcher ?? = utils.createWatcher;
43+ fail ?? = package_test.fail;
44+ printOnFailure ?? = package_test.printOnFailure;
2945
30- // Create the watcher and [ClientSimulator].
31- final watcher = createWatcher (path: temp.path);
32- final client = await ClientSimulator .watch (watcher);
33- addTearDown (client.close);
46+ final temp = Directory .systemTemp.createTempSync ();
47+ addTearDown (() => temp.deleteSync (recursive: true ));
3448
35- // 20 iterations of making changes, waiting for events to settle, and
36- // checking for consistency.
37- final changer = FileChanger (temp.path);
38- for (var i = 0 ; i != 40 ; ++ i) {
39- for (final entity in temp.listSync ()) {
40- entity.deleteSync (recursive: true );
41- }
42- // File changes.
43- final messages = await changer.changeFiles (times: 200 );
49+ // Create the watcher and [ClientSimulator].
50+ final watcher = createWatcher (path: temp.path);
51+ final client = await ClientSimulator .watch (
52+ watcher: watcher, printOnFailure: printOnFailure);
53+ addTearDown (client.close);
4454
45- // Give time for events to arrive. To allow tests to run quickly when the
46- // events are handled quickly, poll and continue if verification passes.
47- for (var waits = 0 ; waits != 20 ; ++ waits) {
48- if (client.verify (log: false )) {
49- break ;
50- }
51- await client.waitForNoEvents (const Duration (milliseconds: 100 ));
55+ // 40 iterations of making changes, waiting for events to settle, and
56+ // checking for consistency.
57+ final changer = FileChanger (temp.path);
58+ for (var i = 0 ; endlessMode || i != 40 ; ++ i) {
59+ if (endlessMode) stdout.write ('.' );
60+ for (final entity in temp.listSync ()) {
61+ entity.deleteSync (recursive: true );
62+ }
63+ // File changes.
64+ final messages = await changer.changeFiles (times: 200 );
65+
66+ // Give time for events to arrive. To allow tests to run quickly when the
67+ // events are handled quickly, poll and continue if verification passes.
68+ var succeeded = false ;
69+ for (var waits = 0 ; waits != 20 ; ++ waits) {
70+ if (client.verify ()) {
71+ succeeded = true ;
72+ break ;
5273 }
74+ await client.waitForNoEvents (const Duration (milliseconds: 100 ));
75+ }
5376
54- // Verify for real and fail the test if still not consistent.
55- if (! client.verify (log: true )) {
56- // Write the file operations before the failure to a log, fail the test.
57- final logTemp = Directory .systemTemp.createTempSync ();
58- final fileChangesLogPath = p.join (logTemp.path, 'changes.txt' );
59- File (fileChangesLogPath)
60- .writeAsStringSync (messages.map ((m) => '$m \n ' ).join ('' ));
61- final clientLogPath = p.join (logTemp.path, 'client.txt' );
62- File (clientLogPath)
63- .writeAsStringSync (client.messages.map ((m) => '$m \n ' ).join ('' ));
64- fail ('''
77+ // Fail the test if still not consistent.
78+ if (! succeeded) {
79+ if (endlessMode) print ('' );
80+ client.verify (printOnFailure: printOnFailure);
81+ // Write the file operations before the failure to a log, fail the test.
82+ final logTemp = Directory .systemTemp.createTempSync ();
83+ final fileChangesLogPath = p.join (logTemp.path, 'changes.txt' );
84+ File (fileChangesLogPath)
85+ .writeAsStringSync (messages.map ((m) => '$m \n ' ).join ('' ));
86+ final clientLogPath = p.join (logTemp.path, 'client.txt' );
87+ File (clientLogPath)
88+ .writeAsStringSync (client.messages.map ((m) => '$m \n ' ).join ('' ));
89+ fail ('''
6590Failed on run $i .
6691Files changes: $fileChangesLogPath
6792Client log: $clientLogPath ''' );
68- }
6993 }
70- });
94+ }
95+ }
96+
97+ /// Main method for running the e2e test without `package:test` .
98+ ///
99+ /// Exits on failure, or runs forever.
100+ Future <void > main () async {
101+ final teardowns = < void Function ()> [];
102+ try {
103+ await _runTest (
104+ addTearDown: teardowns.add,
105+ createWatcher: ({required String path}) => DirectoryWatcher (path),
106+ fail: (message) {
107+ print (message);
108+ exit (1 );
109+ },
110+ printOnFailure: print,
111+ endlessMode: true ,
112+ );
113+ } finally {
114+ for (final teardown in teardowns) {
115+ teardown ();
116+ }
117+ }
71118}
0 commit comments