compile_expression_test.dart 7 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7 8
import 'dart:async';

9
import 'package:file/memory.dart';
10
import 'package:flutter_tools/src/artifacts.dart';
11 12
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart';
13
import 'package:flutter_tools/src/base/logger.dart';
14
import 'package:flutter_tools/src/base/platform.dart';
15
import 'package:flutter_tools/src/build_info.dart';
16 17 18
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:mockito/mockito.dart';
19
import 'package:package_config/package_config.dart';
20
import 'package:process/process.dart';
21 22 23

import '../src/common.dart';
import '../src/context.dart';
24
import '../src/fakes.dart';
25 26 27 28 29

void main() {
  ProcessManager mockProcessManager;
  ResidentCompiler generator;
  MockProcess mockFrontendServer;
30
  MemoryIOSink frontendServerStdIn;
31
  StreamController<String> stdErrStreamController;
32
  BufferLogger testLogger;
33
  MemoryFileSystem fileSystem;
34 35

  setUp(() {
36
    testLogger = BufferLogger.test();
37 38
    mockProcessManager = MockProcessManager();
    mockFrontendServer = MockProcess();
39
    frontendServerStdIn = MemoryIOSink();
40
    fileSystem = MemoryFileSystem.test();
41 42 43 44 45 46
    generator = ResidentCompiler(
      'sdkroot',
      buildMode: BuildMode.debug,
      artifacts: Artifacts.test(),
      processManager: mockProcessManager,
      logger: testLogger,
47
      platform: FakePlatform(operatingSystem: 'linux'),
48
      fileSystem: fileSystem,
49
    );
50

51 52
    stdErrStreamController = StreamController<String>();
    when(mockFrontendServer.stdin).thenReturn(frontendServerStdIn);
53
    when(mockFrontendServer.stderr)
54
        .thenAnswer((Invocation invocation) => stdErrStreamController.stream.transform(utf8.encoder));
55 56 57 58 59 60 61 62 63 64 65
    when(mockFrontendServer.exitCode).thenAnswer((Invocation invocation) {
      return Completer<int>().future;
    });

    when(mockProcessManager.canRun(any)).thenReturn(true);
    when(mockProcessManager.start(any)).thenAnswer(
            (Invocation invocation) =>
        Future<Process>.value(mockFrontendServer)
    );
  });

66
  testWithoutContext('compile expression fails if not previously compiled', () async {
67 68
    final CompilerOutput result = await generator.compileExpression(
        '2+2', null, null, null, null, false);
69

70 71 72
    expect(result, isNull);
  });

73
  testWithoutContext('compile expression can compile single expression', () async {
74 75 76 77
    final Completer<List<int>> compileResponseCompleter =
        Completer<List<int>>();
    final Completer<List<int>> compileExpressionResponseCompleter =
        Completer<List<int>>();
78 79 80
    fileSystem.file('/path/to/main.dart.dill')
      ..createSync(recursive: true)
      ..writeAsBytesSync(<int>[1, 2, 3, 4]);
81 82 83 84 85 86 87 88 89 90 91 92 93

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

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

    await generator.recompile(
94
      Uri.file('/path/to/main.dart'),
95 96
      null, /* invalidatedFiles */
      outputPath: '/build/',
97
      packageConfig: PackageConfig.empty,
98
    ).then((CompilerOutput output) {
99
      expect(frontendServerStdIn.getAndClear(),
100
          'compile file:///path/to/main.dart\n');
101
      expect(testLogger.errorText,
102
          equals('line1\nline2\n'));
103 104 105 106 107 108 109 110 111 112
      expect(output.outputFilename, equals('/path/to/main.dart.dill'));

      compileExpressionResponseCompleter.complete(
          Future<List<int>>.value(utf8.encode(
              'result def\nline1\nline2\ndef\ndef /path/to/main.dart.dill.incremental 0\n'
          )));
      generator.compileExpression(
          '2+2', null, null, null, null, false).then(
              (CompilerOutput outputExpression) {
                expect(outputExpression, isNotNull);
113
                expect(outputExpression.expressionData, <int>[1, 2, 3, 4]);
114 115 116 117 118
              }
      );
    });
  });

119
  testWithoutContext('compile expressions without awaiting', () async {
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
    final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
    final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>();
    final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>();

    when(mockFrontendServer.stdout)
        .thenAnswer((Invocation invocation) =>
    Stream<List<int>>.fromFutures(
        <Future<List<int>>>[
          compileResponseCompleter.future,
          compileExpressionResponseCompleter1.future,
          compileExpressionResponseCompleter2.future,
        ]));

    // The test manages timing via completers.
    unawaited(
      generator.recompile(
136
        Uri.parse('/path/to/main.dart'),
137 138
        null, /* invalidatedFiles */
        outputPath: '/build/',
139
        packageConfig: PackageConfig.empty,
140
      ).then((CompilerOutput outputCompile) {
141
        expect(testLogger.errorText,
142
            equals('line1\nline2\n'));
143 144
        expect(outputCompile.outputFilename, equals('/path/to/main.dart.dill'));

145 146 147
        fileSystem.file('/path/to/main.dart.dill.incremental')
          ..createSync(recursive: true)
          ..writeAsBytesSync(<int>[0, 1, 2, 3]);
148 149 150 151 152 153 154 155 156 157 158 159
        compileExpressionResponseCompleter1.complete(Future<List<int>>.value(utf8.encode(
            'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n'
        )));
      }),
    );

    // The test manages timing via completers.
    final Completer<bool> lastExpressionCompleted = Completer<bool>();
    unawaited(
      generator.compileExpression('0+1', null, null, null, null, false).then(
        (CompilerOutput outputExpression) {
          expect(outputExpression, isNotNull);
160 161 162 163 164
          expect(outputExpression.expressionData, <int>[0, 1, 2, 3]);

          fileSystem.file('/path/to/main.dart.dill.incremental')
            ..createSync(recursive: true)
            ..writeAsBytesSync(<int>[4, 5, 6, 7]);
165 166 167 168 169 170 171 172 173 174 175 176
          compileExpressionResponseCompleter2.complete(Future<List<int>>.value(utf8.encode(
              'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n'
          )));
        },
      ),
    );

    // The test manages timing via completers.
    unawaited(
      generator.compileExpression('1+1', null, null, null, null, false).then(
        (CompilerOutput outputExpression) {
          expect(outputExpression, isNotNull);
177
          expect(outputExpression.expressionData, <int>[4, 5, 6, 7]);
178 179
          lastExpressionCompleted.complete(true);
        },
180
      ),
181 182 183 184 185 186 187 188 189 190 191 192
    );

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

    expect(await lastExpressionCompleted.future, isTrue);
  });
}

class MockProcess extends Mock implements Process {}
class MockProcessManager extends Mock implements ProcessManager {}