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

import 'dart:async';

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

import '../src/common.dart';
21
import '../src/fake_process_manager.dart';
22
import '../src/fakes.dart';
23 24

void main() {
25 26 27 28 29 30
  late FakeProcessManager processManager;
  late ResidentCompiler generator;
  late MemoryIOSink frontendServerStdIn;
  late StreamController<String> stdErrStreamController;
  late BufferLogger testLogger;
  late MemoryFileSystem fileSystem;
31 32

  setUp(() {
33
    testLogger = BufferLogger.test();
34
    processManager = FakeProcessManager();
35
    frontendServerStdIn = MemoryIOSink();
36
    fileSystem = MemoryFileSystem.test();
37 38 39 40
    generator = ResidentCompiler(
      'sdkroot',
      buildMode: BuildMode.debug,
      artifacts: Artifacts.test(),
41
      processManager: processManager,
42
      logger: testLogger,
43
      platform: FakePlatform(),
44
      fileSystem: fileSystem,
45
    );
46

47
    stdErrStreamController = StreamController<String>();
48 49
    processManager.process.stdin = frontendServerStdIn;
    processManager.process.stderr = stdErrStreamController.stream.transform(utf8.encoder);
50 51
  });

52
  testWithoutContext('compile expression fails if not previously compiled', () async {
53
    final CompilerOutput? result = await generator.compileExpression(
54
        '2+2', null, null, null, null, false);
55

56 57 58
    expect(result, isNull);
  });

59
  testWithoutContext('compile expression can compile single expression', () async {
60 61 62 63
    final Completer<List<int>> compileResponseCompleter =
        Completer<List<int>>();
    final Completer<List<int>> compileExpressionResponseCompleter =
        Completer<List<int>>();
64 65 66
    fileSystem.file('/path/to/main.dart.dill')
      ..createSync(recursive: true)
      ..writeAsBytesSync(<int>[1, 2, 3, 4]);
67

68
    processManager.process.stdout = Stream<List<int>>.fromFutures(
69 70
      <Future<List<int>>>[
        compileResponseCompleter.future,
71
        compileExpressionResponseCompleter.future]);
72 73 74 75 76
    compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode(
      'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'
    )));

    await generator.recompile(
77
      Uri.file('/path/to/main.dart'),
78 79
      null, /* invalidatedFiles */
      outputPath: '/build/',
80
      packageConfig: PackageConfig.empty,
81 82
      projectRootPath: '',
      fs: fileSystem,
83
    ).then((CompilerOutput? output) {
84
      expect(frontendServerStdIn.getAndClear(),
85
          'compile file:///path/to/main.dart\n');
86
      expect(testLogger.errorText,
87
          equals('line1\nline2\n'));
88
      expect(output!.outputFilename, equals('/path/to/main.dart.dill'));
89 90 91 92 93 94 95

      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(
96
              (CompilerOutput? outputExpression) {
97
                expect(outputExpression, isNotNull);
98
                expect(outputExpression!.expressionData, <int>[1, 2, 3, 4]);
99 100 101 102 103
              }
      );
    });
  });

104
  testWithoutContext('compile expressions without awaiting', () async {
105 106 107 108
    final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
    final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>();
    final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>();

109 110 111 112 113 114 115 116

    processManager.process.stdout =
      Stream<List<int>>.fromFutures(
          <Future<List<int>>>[
            compileResponseCompleter.future,
            compileExpressionResponseCompleter1.future,
            compileExpressionResponseCompleter2.future,
          ]);
117 118 119 120

    // The test manages timing via completers.
    unawaited(
      generator.recompile(
121
        Uri.parse('/path/to/main.dart'),
122 123
        null, /* invalidatedFiles */
        outputPath: '/build/',
124
        packageConfig: PackageConfig.empty,
125 126
        projectRootPath: '',
        fs: MemoryFileSystem(),
127
      ).then((CompilerOutput? outputCompile) {
128
        expect(testLogger.errorText,
129
            equals('line1\nline2\n'));
130
        expect(outputCompile!.outputFilename, equals('/path/to/main.dart.dill'));
131

132 133 134
        fileSystem.file('/path/to/main.dart.dill.incremental')
          ..createSync(recursive: true)
          ..writeAsBytesSync(<int>[0, 1, 2, 3]);
135 136 137 138 139 140 141 142 143 144
        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(
145
        (CompilerOutput? outputExpression) {
146
          expect(outputExpression, isNotNull);
147
          expect(outputExpression!.expressionData, <int>[0, 1, 2, 3]);
148 149 150 151

          fileSystem.file('/path/to/main.dart.dill.incremental')
            ..createSync(recursive: true)
            ..writeAsBytesSync(<int>[4, 5, 6, 7]);
152 153 154 155 156 157 158 159 160 161
          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(
162
        (CompilerOutput? outputExpression) {
163
          expect(outputExpression, isNotNull);
164
          expect(outputExpression!.expressionData, <int>[4, 5, 6, 7]);
165 166
          lastExpressionCompleted.complete(true);
        },
167
      ),
168 169 170 171 172 173 174 175 176 177
    );

    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);
  });
}

178 179
class FakeProcess extends Fake implements Process {
  @override
180
  Stream<List<int>> stdout = const Stream<List<int>>.empty();
181 182

  @override
183
  Stream<List<int>> stderr = const Stream<List<int>>.empty();
184 185

  @override
186
  IOSink stdin = IOSink(StreamController<List<int>>().sink);
187 188 189 190 191 192 193 194 195

  @override
  Future<int> get exitCode => Completer<int>().future;
}

class FakeProcessManager extends Fake implements ProcessManager {
  final FakeProcess process = FakeProcess();

  @override
196
  bool canRun(dynamic executable, {String? workingDirectory}) {
197 198 199 200
    return true;
  }

  @override
201
  Future<Process> start(List<Object> command, {String? workingDirectory, Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, ProcessStartMode mode = ProcessStartMode.normal}) async {
202 203 204
    return process;
  }
}