compile_test.dart 23.8 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2017 The Chromium 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 'dart:convert';

8
import 'package:flutter_tools/src/base/common.dart';
9
import 'package:flutter_tools/src/base/file_system.dart';
10 11 12
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/logger.dart';
13
import 'package:flutter_tools/src/base/platform.dart';
14
import 'package:flutter_tools/src/base/terminal.dart';
15 16 17 18
import 'package:flutter_tools/src/compile.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';

19
import 'src/common.dart';
20 21
import 'src/context.dart';

22 23
final Generator _kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false;

24
void main() {
25
  group(PackageUriMapper, () {
26 27
    group('single-root', () {
      const String packagesContents = r'''
28 29 30 31
xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
example:file:///example/lib/
''';
32 33 34 35 36 37 38 39 40 41 42
      final MockFileSystem mockFileSystem = MockFileSystem();
      final MockFile mockFile = MockFile();
      when(mockFileSystem.path).thenReturn(fs.path);
      when(mockFileSystem.file(any)).thenReturn(mockFile);
      when(mockFile.readAsBytesSync()).thenReturn(utf8.encode(packagesContents));
      testUsingContext('Can map main.dart to correct package', () async {
        final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
        expect(packageUriMapper.map('/example/lib/main.dart').toString(), 'package:example/main.dart');
      }, overrides: <Type, Generator>{
        FileSystem: () => mockFileSystem,
      });
43

44 45 46 47 48 49
      testUsingContext('Maps file from other package to null', () async {
        final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
        expect(packageUriMapper.map('/xml/lib/xml.dart'),  null);
      }, overrides: <Type, Generator>{
        FileSystem: () => mockFileSystem,
      });
50

51 52 53 54 55 56
      testUsingContext('Maps non-main file from same package', () async {
        final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
        expect(packageUriMapper.map('/example/lib/src/foo.dart').toString(), 'package:example/src/foo.dart');
      }, overrides: <Type, Generator>{
        FileSystem: () => mockFileSystem,
      });
57 58
    });

59 60 61 62 63 64 65 66 67
    group('multi-root', () {
      final MockFileSystem mockFileSystem = MockFileSystem();
      final MockFile mockFile = MockFile();
      when(mockFileSystem.path).thenReturn(fs.path);
      when(mockFileSystem.file(any)).thenReturn(mockFile);

      const String multiRootPackagesContents = r'''
xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
68
example:org-dartlang-app:/
69 70 71 72
''';
      when(mockFile.readAsBytesSync()).thenReturn(utf8.encode(multiRootPackagesContents));

      testUsingContext('Maps main file from same package on multiroot scheme', () async {
73
        final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', 'org-dartlang-app', <String>['/example/lib/', '/gen/lib/']);
74 75 76 77
        expect(packageUriMapper.map('/example/lib/main.dart').toString(), 'package:example/main.dart');
      }, overrides: <Type, Generator>{
        FileSystem: () => mockFileSystem,
      });
78 79 80
    });
  });

81
  testUsingContext('StdOutHandler test', () async {
82 83 84
    final StdoutHandler stdoutHandler = StdoutHandler();
    stdoutHandler.handler('result 12345');
    expect(stdoutHandler.boundaryKey, '12345');
85
    stdoutHandler.handler('12345');
86 87 88 89
    stdoutHandler.handler('12345 message 0');
    final CompilerOutput output = await stdoutHandler.compilerOutput.future;
    expect(output.errorCount, 0);
    expect(output.outputFilename, 'message');
90 91
  }, overrides: <Type, Generator>{
    Logger: () => BufferLogger(),
92 93
  });

94 95 96 97 98 99
  group('batch compile', () {
    ProcessManager mockProcessManager;
    MockProcess mockFrontendServer;
    MockStdIn mockFrontendServerStdIn;
    MockStream mockFrontendServerStdErr;
    setUp(() {
100 101 102 103
      mockProcessManager = MockProcessManager();
      mockFrontendServer = MockProcess();
      mockFrontendServerStdIn = MockStdIn();
      mockFrontendServerStdErr = MockStream();
104

105 106
      when(mockFrontendServer.stderr)
          .thenAnswer((Invocation invocation) => mockFrontendServerStdErr);
107
      final StreamController<String> stdErrStreamController = StreamController<String>();
108
      when(mockFrontendServerStdErr.transform<String>(any)).thenAnswer((_) => stdErrStreamController.stream);
109
      when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
110
      when(mockProcessManager.canRun(any)).thenReturn(true);
111
      when(mockProcessManager.start(any)).thenAnswer(
112
          (Invocation invocation) => Future<Process>.value(mockFrontendServer));
113
      when(mockFrontendServer.exitCode).thenAnswer((_) async => 0);
114 115 116
    });

    testUsingContext('single dart successful compilation', () async {
117
      final BufferLogger logger = context.get<Logger>();
118
      when(mockFrontendServer.stdout)
119 120
          .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
            Future<List<int>>.value(utf8.encode(
121
              'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'
122 123
            ))
          ));
124
      final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(null);
125
      final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
126 127
        mainPath: '/path/to/main.dart',
        trackWidgetCreation: false,
128
      );
129
      expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
130
      expect(logger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
131
      expect(output.outputFilename, equals('/path/to/main.dart.dill'));
132 133
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
134 135
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
136
      Platform: _kNoColorTerminalPlatform,
137 138 139
    });

    testUsingContext('single dart failed compilation', () async {
140
      final BufferLogger logger = context.get<Logger>();
141

142
      when(mockFrontendServer.stdout)
143 144
          .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
            Future<List<int>>.value(utf8.encode(
145
              'result abc\nline1\nline2\nabc\nabc'
146 147
            ))
          ));
148
      final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(null);
149
      final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
150 151
        mainPath: '/path/to/main.dart',
        trackWidgetCreation: false,
152
      );
153
      expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
154
      expect(logger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
155 156 157
      expect(output, equals(null));
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
158 159
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
160
      Platform: _kNoColorTerminalPlatform,
161
    });
162 163

    testUsingContext('single dart abnormal compiler termination', () async {
164
      when(mockFrontendServer.exitCode).thenAnswer((_) async => 255);
165

166
      final BufferLogger logger = context.get<Logger>();
167 168

      when(mockFrontendServer.stdout)
169 170
          .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
          Future<List<int>>.value(utf8.encode(
171
              'result abc\nline1\nline2\nabc\nabc'
172 173
          ))
      ));
174
      final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(null);
175 176 177 178
      final CompilerOutput output = await kernelCompiler.compile(
        sdkRoot: '/path/to/sdkroot',
        mainPath: '/path/to/main.dart',
        trackWidgetCreation: false,
179 180
      );
      expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
181
      expect(logger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
182 183 184
      expect(output, equals(null));
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
185 186
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
187
      Platform: _kNoColorTerminalPlatform,
188
    });
189 190 191 192 193 194 195 196 197 198 199
  });

  group('incremental compile', () {
    ProcessManager mockProcessManager;
    ResidentCompiler generator;
    MockProcess mockFrontendServer;
    MockStdIn mockFrontendServerStdIn;
    MockStream mockFrontendServerStdErr;
    StreamController<String> stdErrStreamController;

    setUp(() {
200 201 202 203 204
      generator = ResidentCompiler('sdkroot');
      mockProcessManager = MockProcessManager();
      mockFrontendServer = MockProcess();
      mockFrontendServerStdIn = MockStdIn();
      mockFrontendServerStdErr = MockStream();
205 206

      when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
207 208
      when(mockFrontendServer.stderr)
          .thenAnswer((Invocation invocation) => mockFrontendServerStdErr);
209
      stdErrStreamController = StreamController<String>();
210 211
      when(mockFrontendServerStdErr.transform<String>(any))
          .thenAnswer((Invocation invocation) => stdErrStreamController.stream);
212

213
      when(mockProcessManager.canRun(any)).thenReturn(true);
214
      when(mockProcessManager.start(any)).thenAnswer(
215
          (Invocation invocation) => Future<Process>.value(mockFrontendServer)
216
      );
217 218 219 220
    });

    tearDown(() {
      verifyNever(mockFrontendServer.exitCode);
221 222 223
    });

    testUsingContext('single dart compile', () async {
224
      final BufferLogger logger = context.get<Logger>();
225

226
      when(mockFrontendServer.stdout)
227 228
          .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
            Future<List<int>>.value(utf8.encode(
229
              'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0'
230 231
            ))
          ));
232

233
      final CompilerOutput output = await generator.recompile(
234 235 236
        '/path/to/main.dart',
          null /* invalidatedFiles */,
        outputPath: '/build/',
237
      );
238
      expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
239
      verifyNoMoreInteractions(mockFrontendServerStdIn);
240
      expect(logger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
241
      expect(output.outputFilename, equals('/path/to/main.dart.dill'));
242 243
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
244 245
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
246
      Platform: _kNoColorTerminalPlatform,
247 248
    });

249 250 251 252 253
    testUsingContext('single dart compile abnormally terminates', () async {
      when(mockFrontendServer.stdout)
          .thenAnswer((Invocation invocation) => const Stream<List<int>>.empty()
      );

254
      final CompilerOutput output = await generator.recompile(
255 256 257
        '/path/to/main.dart',
        null, /* invalidatedFiles */
        outputPath: '/build/',
258 259 260 261
      );
      expect(output, equals(null));
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
262 263
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
264
      Platform: _kNoColorTerminalPlatform,
265 266
    });

267
    testUsingContext('compile and recompile', () async {
268
      final BufferLogger logger = context.get<Logger>();
269

270
      final StreamController<List<int>> streamController = StreamController<List<int>>();
271 272
      when(mockFrontendServer.stdout)
          .thenAnswer((Invocation invocation) => streamController.stream);
273
      streamController.add(utf8.encode('result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n'));
274 275 276 277 278
      await generator.recompile(
        '/path/to/main.dart',
        null, /* invalidatedFiles */
        outputPath: '/build/',
      );
279
      expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
280

281 282 283 284 285
      // No accept or reject commands should be issued until we
      // send recompile request.
      await _accept(streamController, generator, mockFrontendServerStdIn, '');
      await _reject(streamController, generator, mockFrontendServerStdIn, '', '');

286
      await _recompile(streamController, generator, mockFrontendServerStdIn,
287
        'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n');
288

289 290 291
      await _accept(streamController, generator, mockFrontendServerStdIn, '^accept\\n\$');

      await _recompile(streamController, generator, mockFrontendServerStdIn,
292
          'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n');
293

294
      await _reject(streamController, generator, mockFrontendServerStdIn, 'result abc\nabc\nabc\nabc',
295 296
          '^reject\\n\$');

297
      verifyNoMoreInteractions(mockFrontendServerStdIn);
298
      expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
299
      expect(logger.errorText, equals(
300 301
        '\nCompiler message:\nline0\nline1\n'
        '\nCompiler message:\nline1\nline2\n'
302
        '\nCompiler message:\nline1\nline2\n'
303
      ));
304 305
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
306 307
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
308
      Platform: _kNoColorTerminalPlatform,
309
    });
310

311
    testUsingContext('compile and recompile twice', () async {
312
      final BufferLogger logger = context.get<Logger>();
313

314
      final StreamController<List<int>> streamController = StreamController<List<int>>();
315 316
      when(mockFrontendServer.stdout)
          .thenAnswer((Invocation invocation) => streamController.stream);
317
      streamController.add(utf8.encode(
318
        'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n'
319
      ));
320
      await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */, outputPath: '/build/');
321
      expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
322

323
      await _recompile(streamController, generator, mockFrontendServerStdIn,
324
        'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n');
325
      await _recompile(streamController, generator, mockFrontendServerStdIn,
326
        'result abc\nline2\nline3\nabc\nabc /path/to/main.dart.dill 0\n');
327

328
      verifyNoMoreInteractions(mockFrontendServerStdIn);
329
      expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
330
      expect(logger.errorText, equals(
331 332 333
        '\nCompiler message:\nline0\nline1\n'
        '\nCompiler message:\nline1\nline2\n'
        '\nCompiler message:\nline2\nline3\n'
334
      ));
335 336
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
337 338
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
339
      Platform: _kNoColorTerminalPlatform,
340 341
    });
  });
342

343
  group('compile expression', () {
344 345 346 347 348 349 350 351
    ProcessManager mockProcessManager;
    ResidentCompiler generator;
    MockProcess mockFrontendServer;
    MockStdIn mockFrontendServerStdIn;
    MockStream mockFrontendServerStdErr;
    StreamController<String> stdErrStreamController;

    setUp(() {
352 353 354 355 356
      generator = ResidentCompiler('sdkroot');
      mockProcessManager = MockProcessManager();
      mockFrontendServer = MockProcess();
      mockFrontendServerStdIn = MockStdIn();
      mockFrontendServerStdErr = MockStream();
357 358 359 360

      when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
      when(mockFrontendServer.stderr)
          .thenAnswer((Invocation invocation) => mockFrontendServerStdErr);
361
      stdErrStreamController = StreamController<String>();
362 363 364 365 366 367
      when(mockFrontendServerStdErr.transform<String>(any))
          .thenAnswer((Invocation invocation) => stdErrStreamController.stream);

      when(mockProcessManager.canRun(any)).thenReturn(true);
      when(mockProcessManager.start(any)).thenAnswer(
              (Invocation invocation) =>
368
          Future<Process>.value(mockFrontendServer)
369 370 371 372 373 374 375 376 377 378 379 380 381 382
      );
    });

    tearDown(() {
      verifyNever(mockFrontendServer.exitCode);
    });

    testUsingContext('fails if not previously compiled', () async {
      final CompilerOutput result = await generator.compileExpression(
          '2+2', null, null, null, null, false);
      expect(result, isNull);
    });

    testUsingContext('compile single expression', () async {
383
      final BufferLogger logger = context.get<Logger>();
384 385

      final Completer<List<int>> compileResponseCompleter =
386
          Completer<List<int>>();
387
      final Completer<List<int>> compileExpressionResponseCompleter =
388
          Completer<List<int>>();
389 390 391

      when(mockFrontendServer.stdout)
          .thenAnswer((Invocation invocation) =>
392
      Stream<List<int>>.fromFutures(
393 394 395 396
        <Future<List<int>>>[
          compileResponseCompleter.future,
          compileExpressionResponseCompleter.future]));

397
      compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode(
398
        'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'
399 400
      )));

401
      await generator.recompile(
402 403 404
        '/path/to/main.dart',
        null, /* invalidatedFiles */
        outputPath: '/build/',
405 406 407 408 409
      ).then((CompilerOutput output) {
        expect(mockFrontendServerStdIn.getAndClear(),
            'compile /path/to/main.dart\n');
        verifyNoMoreInteractions(mockFrontendServerStdIn);
        expect(logger.errorText,
410
            equals('\nCompiler message:\nline1\nline2\n'));
411 412 413
        expect(output.outputFilename, equals('/path/to/main.dart.dill'));

        compileExpressionResponseCompleter.complete(
414
            Future<List<int>>.value(utf8.encode(
415
                'result def\nline1\nline2\ndef\ndef /path/to/main.dart.dill.incremental 0\n'
416 417 418 419 420 421 422 423 424 425 426 427 428
            )));
        generator.compileExpression(
            '2+2', null, null, null, null, false).then(
                (CompilerOutput outputExpression) {
                  expect(outputExpression, isNotNull);
                  expect(outputExpression.outputFilename, equals('/path/to/main.dart.dill.incremental'));
                  expect(outputExpression.errorCount, 0);
                }
        );
      });

    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
429 430
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
431
      Platform: _kNoColorTerminalPlatform,
432 433 434
    });

    testUsingContext('compile expressions without awaiting', () async {
435
      final BufferLogger logger = context.get<Logger>();
436

437 438 439
      final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
      final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>();
      final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>();
440 441 442

      when(mockFrontendServer.stdout)
          .thenAnswer((Invocation invocation) =>
443
      Stream<List<int>>.fromFutures(
444 445 446 447 448 449
          <Future<List<int>>>[
            compileResponseCompleter.future,
            compileExpressionResponseCompleter1.future,
            compileExpressionResponseCompleter2.future,
          ]));

450
      // The test manages timing via completers.
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
      unawaited(
        generator.recompile(
          '/path/to/main.dart',
          null, /* invalidatedFiles */
          outputPath: '/build/',
        ).then((CompilerOutput outputCompile) {
          expect(logger.errorText,
              equals('\nCompiler message:\nline1\nline2\n'));
          expect(outputCompile.outputFilename, equals('/path/to/main.dart.dill'));

          compileExpressionResponseCompleter1.complete(Future<List<int>>.value(utf8.encode(
              'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n'
          )));
        }),
      );
466

467
      // The test manages timing via completers.
468
      final Completer<bool> lastExpressionCompleted = Completer<bool>();
469 470
      unawaited(
        generator.compileExpression('0+1', null, null, null, null, false).then(
471 472 473 474 475
          (CompilerOutput outputExpression) {
            expect(outputExpression, isNotNull);
            expect(outputExpression.outputFilename,
                equals('/path/to/main.dart.dill.incremental'));
            expect(outputExpression.errorCount, 0);
476
            compileExpressionResponseCompleter2.complete(Future<List<int>>.value(utf8.encode(
477 478
                'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n'
            )));
479 480 481
          },
        ),
      );
482

483
      // The test manages timing via completers.
484 485
      unawaited(
        generator.compileExpression('1+1', null, null, null, null, false).then(
486 487 488 489 490 491
          (CompilerOutput outputExpression) {
            expect(outputExpression, isNotNull);
            expect(outputExpression.outputFilename,
                equals('/path/to/main.dart.dill.incremental'));
            expect(outputExpression.errorCount, 0);
            lastExpressionCompleted.complete(true);
492 493 494
          },
        )
      );
495

496
      compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode(
497
          'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'
498 499
      )));

500
      expect(await lastExpressionCompleted.future, isTrue);
501 502
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
503 504
      OutputPreferences: () => OutputPreferences(showColor: false),
      Logger: () => BufferLogger(),
505
      Platform: _kNoColorTerminalPlatform,
506 507
    });
  });
508 509
}

510 511 512 513 514 515
Future<void> _recompile(
  StreamController<List<int>> streamController,
  ResidentCompiler generator,
  MockStdIn mockFrontendServerStdIn,
  String mockCompilerOutput,
) async {
516 517
  // Put content into the output stream after generator.recompile gets
  // going few lines below, resets completer.
518
  scheduleMicrotask(() {
519
    streamController.add(utf8.encode(mockCompilerOutput));
520
  });
521 522
  final CompilerOutput output = await generator.recompile(
    null /* mainPath */,
523
    <Uri>[Uri.parse('/path/to/main.dart')],
524 525
    outputPath: '/build/',
  );
526
  expect(output.outputFilename, equals('/path/to/main.dart.dill'));
527
  final String commands = mockFrontendServerStdIn.getAndClear();
528
  final RegExp re = RegExp('^recompile (.*)\\n/path/to/main.dart\\n(.*)\\n\$');
529 530 531 532
  expect(commands, matches(re));
  final Match match = re.firstMatch(commands);
  expect(match[1] == match[2], isTrue);
  mockFrontendServerStdIn._stdInWrites.clear();
533 534
}

535 536 537 538 539 540
Future<void> _accept(
  StreamController<List<int>> streamController,
  ResidentCompiler generator,
  MockStdIn mockFrontendServerStdIn,
  String expected,
) async {
541 542 543 544 545 546 547 548 549
  // Put content into the output stream after generator.recompile gets
  // going few lines below, resets completer.
  generator.accept();
  final String commands = mockFrontendServerStdIn.getAndClear();
  final RegExp re = RegExp(expected);
  expect(commands, matches(re));
  mockFrontendServerStdIn._stdInWrites.clear();
}

550 551 552 553 554 555 556
Future<void> _reject(
  StreamController<List<int>> streamController,
  ResidentCompiler generator,
  MockStdIn mockFrontendServerStdIn,
  String mockCompilerOutput,
  String expected,
) async {
557 558 559 560 561 562 563 564 565 566 567 568 569
  // Put content into the output stream after generator.recompile gets
  // going few lines below, resets completer.
  scheduleMicrotask(() {
    streamController.add(utf8.encode(mockCompilerOutput));
  });
  final CompilerOutput output = await generator.reject();
  expect(output, isNull);
  final String commands = mockFrontendServerStdIn.getAndClear();
  final RegExp re = RegExp(expected);
  expect(commands, matches(re));
  mockFrontendServerStdIn._stdInWrites.clear();
}

570 571 572
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockStream extends Mock implements Stream<List<int>> {}
573
class MockStdIn extends Mock implements IOSink {
574
  final StringBuffer _stdInWrites = StringBuffer();
575 576 577 578 579 580 581 582

  String getAndClear() {
    final String result = _stdInWrites.toString();
    _stdInWrites.clear();
    return result;
  }

  @override
583
  void write([ Object o = '' ]) {
584 585 586 587
    _stdInWrites.write(o);
  }

  @override
588
  void writeln([ Object o = '' ]) {
589 590 591
    _stdInWrites.writeln(o);
  }
}
592 593
class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {}