flutter/packages/flutter_tools/test/general.shard/compile_expression_test.dart
Michael Goderbauer 5491c8c146
Auto-format Framework (#160545)
This auto-formats all *.dart files in the repository outside of the
`engine` subdirectory and enforces that these files stay formatted with
a presubmit check.

**Reviewers:** Please carefully review all the commits except for the
one titled "formatted". The "formatted" commit was auto-generated by
running `dev/tools/format.sh -a -f`. The other commits were hand-crafted
to prepare the repo for the formatting change. I recommend reviewing the
commits one-by-one via the "Commits" tab and avoiding Github's "Files
changed" tab as it will likely slow down your browser because of the
size of this PR.

---------

Co-authored-by: Kate Lovett <katelovett@google.com>
Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
2024-12-19 20:06:21 +00:00

233 lines
7.7 KiB
Dart

// Copyright 2014 The Flutter 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 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'package:test/fake.dart';
import '../src/common.dart';
import '../src/fake_process_manager.dart';
import '../src/fakes.dart';
void main() {
late FakeProcessManager processManager;
late ResidentCompiler generator;
late MemoryIOSink frontendServerStdIn;
late StreamController<String> stdErrStreamController;
late BufferLogger testLogger;
late MemoryFileSystem fileSystem;
setUp(() {
testLogger = BufferLogger.test();
processManager = FakeProcessManager();
frontendServerStdIn = MemoryIOSink();
fileSystem = MemoryFileSystem.test();
generator = ResidentCompiler(
'sdkroot',
buildMode: BuildMode.debug,
artifacts: Artifacts.test(),
processManager: processManager,
logger: testLogger,
platform: FakePlatform(),
fileSystem: fileSystem,
);
stdErrStreamController = StreamController<String>();
processManager.process.stdin = frontendServerStdIn;
processManager.process.stderr = stdErrStreamController.stream.transform(utf8.encoder);
});
testWithoutContext('compile expression fails if not previously compiled', () async {
final CompilerOutput? result = await generator.compileExpression(
'2+2',
null,
null,
null,
null,
null,
null,
null,
null,
false,
);
expect(result, isNull);
});
testWithoutContext('compile expression can compile single expression', () async {
final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter = Completer<List<int>>();
fileSystem.file('/path/to/main.dart.dill')
..createSync(recursive: true)
..writeAsBytesSync(<int>[1, 2, 3, 4]);
processManager.process.stdout = 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(
Uri.file('/path/to/main.dart'),
null,
/* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
projectRootPath: '',
fs: fileSystem,
)
.then((CompilerOutput? output) {
expect(frontendServerStdIn.getAndClear(), 'compile file:///path/to/main.dart\n');
expect(testLogger.errorText, equals('line1\nline2\n'));
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, null, null, null, null, false)
.then((CompilerOutput? outputExpression) {
expect(outputExpression, isNotNull);
expect(outputExpression!.expressionData, <int>[1, 2, 3, 4]);
});
});
});
testWithoutContext('compile expressions without awaiting', () async {
final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>();
processManager.process.stdout = Stream<List<int>>.fromFutures(<Future<List<int>>>[
compileResponseCompleter.future,
compileExpressionResponseCompleter1.future,
compileExpressionResponseCompleter2.future,
]);
// The test manages timing via completers.
unawaited(
generator
.recompile(
Uri.parse('/path/to/main.dart'),
null,
/* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
projectRootPath: '',
fs: MemoryFileSystem(),
)
.then((CompilerOutput? outputCompile) {
expect(testLogger.errorText, equals('line1\nline2\n'));
expect(outputCompile!.outputFilename, equals('/path/to/main.dart.dill'));
fileSystem.file('/path/to/main.dart.dill.incremental')
..createSync(recursive: true)
..writeAsBytesSync(<int>[0, 1, 2, 3]);
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, null, null, null, null, false)
.then((CompilerOutput? outputExpression) {
expect(outputExpression, isNotNull);
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]);
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, null, null, null, null, false)
.then((CompilerOutput? outputExpression) {
expect(outputExpression, isNotNull);
expect(outputExpression!.expressionData, <int>[4, 5, 6, 7]);
lastExpressionCompleted.complete(true);
}),
);
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 FakeProcess extends Fake implements Process {
@override
Stream<List<int>> stdout = const Stream<List<int>>.empty();
@override
Stream<List<int>> stderr = const Stream<List<int>>.empty();
@override
IOSink stdin = IOSink(StreamController<List<int>>().sink);
@override
Future<int> get exitCode => Completer<int>().future;
}
class FakeProcessManager extends Fake implements ProcessManager {
final FakeProcess process = FakeProcess();
@override
bool canRun(dynamic executable, {String? workingDirectory}) {
return true;
}
@override
Future<Process> start(
List<Object> command, {
String? workingDirectory,
Map<String, String>? environment,
bool includeParentEnvironment = true,
bool runInShell = false,
ProcessStartMode mode = ProcessStartMode.normal,
}) async {
return process;
}
}