diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart index dfdb85cc979..82713a6885a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/android.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart @@ -192,7 +192,6 @@ class AndroidAot extends AotElfBase { List get inputs => [ const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/android.dart'), const Source.pattern('{BUILD_DIR}/app.dill'), - const Source.pattern('{PROJECT_DIR}/.packages'), const Source.artifact(Artifact.engineDartBinary), const Source.artifact(Artifact.skyEnginePath), Source.artifact(Artifact.genSnapshot, diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 7c978656cd7..b4612fc466d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -161,8 +161,12 @@ class ReleaseCopyFlutterBundle extends CopyFlutterBundle { List get dependencies => const []; } - /// Generate a snapshot of the dart code used in the program. +/// +/// Note that this target depends on the `.dart_tool/package_config.json` file +/// even though it is not listed as an input. Pub inserts a timestamp into +/// the file which causes unecessary rebuilds, so instead a subset of the contents +/// are used an input instead. class KernelSnapshot extends Target { const KernelSnapshot(); @@ -171,7 +175,7 @@ class KernelSnapshot extends Target { @override List get inputs => const [ - Source.pattern('{PROJECT_DIR}/.packages'), + Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'), Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), Source.artifact(Artifact.platformKernelDill), Source.artifact(Artifact.engineDartBinary), @@ -209,7 +213,9 @@ class KernelSnapshot extends Target { } final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final String targetFile = environment.defines[kTargetFile] ?? environment.fileSystem.path.join('lib', 'main.dart'); - final File packagesFile = environment.projectDir.childFile('.packages'); + final File packagesFile = environment.projectDir + .childDirectory('.dart_tool') + .childFile('package_config.json'); final String targetFileAbsolute = environment.fileSystem.file(targetFile).absolute.path; // everything besides 'false' is considered to be enabled. final bool trackWidgetCreation = environment.defines[kTrackWidgetCreation] != 'false'; @@ -240,7 +246,7 @@ class KernelSnapshot extends Target { } final PackageConfig packageConfig = await loadPackageConfigWithLogging( - environment.projectDir.childFile('.packages'), + packagesFile, logger: environment.logger, ); @@ -341,7 +347,6 @@ class AotElfProfile extends AotElfBase { List get inputs => [ const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), const Source.pattern('{BUILD_DIR}/app.dill'), - const Source.pattern('{PROJECT_DIR}/.packages'), const Source.artifact(Artifact.engineDartBinary), const Source.artifact(Artifact.skyEnginePath), Source.artifact(Artifact.genSnapshot, @@ -374,7 +379,6 @@ class AotElfRelease extends AotElfBase { List get inputs => [ const Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), const Source.pattern('{BUILD_DIR}/app.dill'), - const Source.pattern('{PROJECT_DIR}/.packages'), const Source.artifact(Artifact.engineDartBinary), const Source.artifact(Artifact.skyEnginePath), Source.artifact(Artifact.genSnapshot, diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 9bff641361c..9830ff414d5 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -250,10 +250,11 @@ class _DefaultPub implements Pub { 'The time now is: $now' ); } - // Insert references to synthetic flutter package. - if (generateSyntheticPackage) { - await _updatePackageConfig(packageConfigFile, generatedDirectory); - } + await _updatePackageConfig( + packageConfigFile, + generatedDirectory, + generateSyntheticPackage, + ); } @override @@ -458,13 +459,35 @@ class _DefaultPub implements Pub { return environment; } - /// Insert the flutter_gen synthetic package into the package configuration file if - /// there is an l10n.yaml. - Future _updatePackageConfig(File packageConfigFile, Directory generatedDirectory) async { - if (!packageConfigFile.existsSync()) { + /// Update the package configuration file. + /// + /// Creates a corresponding `package_config_subset` file that is used by the build + /// system to avoid rebuilds caused by an updated pub timestamp. + /// + /// if [generateSyntheticPackage] is true then insert flutter_gen synthetic + /// package into the package configuration. This is used by the l10n localization + /// tooling to insert a new reference into the package_config file, allowing the import + /// of a package URI that is not specified in the pubspec.yaml + /// + /// For more information, see: + /// * [generateLocalizations], `in lib/src/localizations/gen_l10n.dart` + Future _updatePackageConfig( + File packageConfigFile, + Directory generatedDirectory, + bool generateSyntheticPackage, + ) async { + final PackageConfig packageConfig = await loadPackageConfigWithLogging(packageConfigFile, logger: _logger); + + packageConfigFile.parent + .childFile('package_config_subset') + .writeAsStringSync(_computePackageConfigSubset( + packageConfig, + _fileSystem, + )); + + if (!generateSyntheticPackage) { return; } - final PackageConfig packageConfig = await loadPackageConfigWithLogging(packageConfigFile, logger: _logger); final Package flutterGen = Package('flutter_gen', generatedDirectory.uri, languageVersion: LanguageVersion(2, 8)); if (packageConfig.packages.any((Package package) => package.name == 'flutter_gen')) { return; @@ -480,4 +503,18 @@ class _DefaultPub implements Pub { await savePackageConfig(newPackageConfig, packageConfigFile.parent.parent); } } + + // Subset the package config file to only the parts that are relevant for + // rerunning the dart compiler. + String _computePackageConfigSubset(PackageConfig packageConfig, FileSystem fileSystem) { + final StringBuffer buffer = StringBuffer(); + for (final Package package in packageConfig.packages) { + buffer.writeln(package.name); + buffer.writeln(package.languageVersion); + buffer.writeln(package.root); + buffer.writeln(package.packageUriRoot); + } + buffer.writeln(packageConfig.version); + return buffer.toString(); + } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart index badc6932cbd..16fa0e02591 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart @@ -117,7 +117,6 @@ void main() { platform: const LocalPlatform(), usage: globals.flutterUsage, botDetector: globals.botDetector, - toolStampFile: () => globals.fs.file('test'), ); await pub.get( context: PubContext.flutterTests, diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart similarity index 94% rename from packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart rename to packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 36d61222300..c5d88a195f2 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -72,7 +72,9 @@ void main() { }); testWithoutContext('KernelSnapshot handles null result from kernel compilation', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -91,7 +93,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -106,7 +108,9 @@ void main() { }); testWithoutContext('KernelSnapshot does not use track widget creation on profile builds', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -125,7 +129,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -140,7 +144,9 @@ void main() { }); testWithoutContext('KernelSnapshot correctly handles an empty string in ExtraFrontEndOptions', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -159,7 +165,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -175,7 +181,9 @@ void main() { }); testWithoutContext('KernelSnapshot correctly forwards ExtraFrontEndOptions', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -194,7 +202,7 @@ void main() { '--aot', '--tfa', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -212,7 +220,9 @@ void main() { }); testWithoutContext('KernelSnapshot can disable track-widget-creation on debug builds', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -230,7 +240,7 @@ void main() { ...buildModeOptions(BuildMode.debug), '--no-link-platform', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -247,7 +257,9 @@ void main() { }); testWithoutContext('KernelSnapshot forces platform linking on debug for darwin target platforms', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final String build = androidEnvironment.buildDir.path; processManager.addCommands([ FakeCommand(command: [ @@ -264,7 +276,7 @@ void main() { '-Ddart.developer.causal_async_stacks=true', ...buildModeOptions(BuildMode.debug), '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', @@ -283,7 +295,9 @@ void main() { }); testWithoutContext('KernelSnapshot does use track widget creation on debug builds', () async { - fileSystem.file('.packages').writeAsStringSync('\n'); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); final Environment testEnvironment = Environment.test( fileSystem.currentDirectory, defines: { @@ -313,7 +327,7 @@ void main() { '--track-widget-creation', '--no-link-platform', '--packages', - '/.packages', + '/.dart_tool/package_config.json', '--output-dill', '$build/app.dill', '--depfile', diff --git a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart index 26ea2f0ff02..1b76f9d8e8e 100644 --- a/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart +++ b/packages/flutter_tools/test/general.shard/dart/pub_get_test.dart @@ -223,6 +223,52 @@ void main() { verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1); }); + testWithoutContext('package_config_subset file is generated from packages and not timestamp', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final MockUsage usage = MockUsage(); + final Pub pub = Pub( + fileSystem: fileSystem, + logger: BufferLogger.test(), + processManager: MockProcessManager(0), + botDetector: const BotDetectorAlwaysNo(), + usage: usage, + platform: FakePlatform( + environment: const { + 'PUB_CACHE': 'custom/pub-cache/path', + } + ), + ); + fileSystem.file('pubspec.yaml').createSync(); + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync(''' + {"configVersion": 2,"packages": [ + { + "name": "flutter_tools", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "2.7" + } + ],"generated":"some-time"} +'''); + + await pub.get( + context: PubContext.flutterTests, + generateSyntheticPackage: true, + checkLastModified: false, + ); + + expect( + fileSystem.file('.dart_tool/package_config_subset').readAsStringSync(), + 'flutter_tools\n' + '2.7\n' + 'file:///\n' + 'file:///lib/\n' + '2\n', + ); + }); + + testWithoutContext('analytics sent on failure', () async { MockDirectory.findCache = true; final MockUsage usage = MockUsage(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/test_test.dart b/packages/flutter_tools/test/integration.shard/test_test.dart similarity index 69% rename from packages/flutter_tools/test/commands.shard/permeable/test_test.dart rename to packages/flutter_tools/test/integration.shard/test_test.dart index 87796974475..15aab8af2aa 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/test_test.dart +++ b/packages/flutter_tools/test/integration.shard/test_test.dart @@ -5,79 +5,84 @@ import 'dart:async'; import 'dart:convert'; -import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import '../../src/common.dart'; -import '../../src/context.dart'; +import '../src/common.dart'; +import 'test_utils.dart'; // This test depends on some files in ///dev/automated_tests/flutter_test/* -Future _testExclusionLock; +final String automatedTestsDirectory = fileSystem.path.join('..', '..', 'dev', 'automated_tests'); +final String missingDependencyDirectory = fileSystem.path.join('..', '..', 'dev', 'missing_dependency_tests'); +final String flutterTestDirectory = fileSystem.path.join(automatedTestsDirectory, 'flutter_test'); +final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); void main() { - final String automatedTestsDirectory = globals.fs.path.join('..', '..', 'dev', 'automated_tests'); - final String flutterTestDirectory = globals.fs.path.join(automatedTestsDirectory, 'flutter_test'); + setUpAll(() async { + await processManager.run( + [ + flutterBin, + 'pub', + 'get' + ], + workingDirectory: flutterTestDirectory + ); + await processManager.run( + [ + flutterBin, + 'pub', + 'get' + ], + workingDirectory: missingDependencyDirectory + ); + }); - testUsingContext('flutter test should not have extraneous error messages', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should not have extraneous error messages', () async { return _testFile('trivial_widget', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero); }); - testUsingContext('flutter test should report nice errors for exceptions thrown within testWidgets()', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report nice errors for exceptions thrown within testWidgets()', () async { return _testFile('exception_handling', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when a guarded function was called without await', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when a guarded function was called without await', () async { return _testFile('test_async_utils_guarded', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when an async function was called without await', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when an async function was called without await', () async { return _testFile('test_async_utils_unguarded', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when a Ticker is left running', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when a Ticker is left running', () async { return _testFile('ticker', automatedTestsDirectory, flutterTestDirectory); }); - testUsingContext('flutter test should report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async { - final String missingDependencyTests = globals.fs.path.join('..', '..', 'dev', 'missing_dependency_tests'); - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async { + final String missingDependencyTests = fileSystem.path.join('..', '..', 'dev', 'missing_dependency_tests'); return _testFile('trivial', missingDependencyTests, missingDependencyTests); }); - testUsingContext('flutter test should report which user-created widget caused the error', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report which user-created widget caused the error', () async { return _testFile('print_user_created_ancestor', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--track-widget-creation']); }); - testUsingContext('flutter test should report which user-created widget caused the error - no flag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report which user-created widget caused the error - no flag', () async { return _testFile('print_user_created_ancestor_no_flag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--no-track-widget-creation']); }); - testUsingContext('flutter test should report the correct user-created widget that caused the error', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should report the correct user-created widget that caused the error', () async { return _testFile('print_correct_local_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--track-widget-creation']); }); - testUsingContext('flutter test should can load assets within its own package', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should can load assets within its own package', () async { return _testFile('package_assets', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero); }); - testUsingContext('flutter test should run a test when its name matches a regexp', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a test when its name matches a regexp', () async { final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--name', 'inc.*de']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -86,8 +91,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run a test when its name contains a string', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a test when its name contains a string', () async { final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--plain-name', 'include']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -96,8 +100,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run a test with a given tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a test with a given tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--tags', 'include-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -106,8 +109,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should not run a test with excluded tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should not run a test with excluded tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--exclude-tags', 'exclude-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -116,8 +118,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run all tests when tags are unspecified', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run all tests when tags are unspecified', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory); if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); @@ -125,8 +126,7 @@ void main() { expect(result.exitCode, 1); }); - testUsingContext('flutter test should run a widgetTest with a given tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run a widgetTest with a given tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--tags', 'include-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -135,8 +135,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should not run a widgetTest with excluded tag', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should not run a widgetTest with excluded tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--exclude-tags', 'exclude-tag']); if (!(result.stdout as String).contains('+1: All tests passed')) { @@ -145,8 +144,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run all widgetTest when tags are unspecified', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run all widgetTest when tags are unspecified', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory); if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); @@ -154,8 +152,7 @@ void main() { expect(result.exitCode, 1); }); - testUsingContext('flutter test should test runs to completion', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should test runs to completion', () async { final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory, extraArguments: const ['--verbose']); final String stdout = result.stdout as String; @@ -172,8 +169,7 @@ void main() { expect(result.exitCode, 0); }); - testUsingContext('flutter test should run all tests inside of a directory with no trailing slash', () async { - Cache.flutterRoot = '../..'; + testWithoutContext('flutter test should run all tests inside of a directory with no trailing slash', () async { final ProcessResult result = await _runFlutterTest(null, automatedTestsDirectory, flutterTestDirectory + '/child_directory', extraArguments: const ['--verbose']); final String stdout = result.stdout as String; @@ -199,16 +195,12 @@ Future _testFile( List extraArguments = const [], }) async { exitCode ??= isNonZero; - final String fullTestExpectation = globals.fs.path.join(testDirectory, '${testName}_expectation.txt'); - final File expectationFile = globals.fs.file(fullTestExpectation); + final String fullTestExpectation = fileSystem.path.join(testDirectory, '${testName}_expectation.txt'); + final File expectationFile = fileSystem.file(fullTestExpectation); if (!expectationFile.existsSync()) { fail('missing expectation file: $expectationFile'); } - while (_testExclusionLock != null) { - await _testExclusionLock; - } - final ProcessResult exec = await _runFlutterTest( testName, workingDirectory, @@ -226,7 +218,7 @@ Future _testFile( } output.add('<>'); output.addAll((exec.stderr as String).split('\n')); - final List expectations = globals.fs.file(fullTestExpectation).readAsLinesSync(); + final List expectations = fileSystem.file(fullTestExpectation).readAsLinesSync(); bool allowSkip = false; int expectationLineNumber = 0; int outputLineNumber = 0; @@ -288,44 +280,33 @@ Future _runFlutterTest( if (testName == null) { // Test everything in the directory. testPath = testDirectory; - final Directory directoryToTest = globals.fs.directory(testPath); + final Directory directoryToTest = fileSystem.directory(testPath); if (!directoryToTest.existsSync()) { fail('missing test directory: $directoryToTest'); } } else { // Test just a specific test file. - testPath = globals.fs.path.join(testDirectory, '${testName}_test.dart'); - final File testFile = globals.fs.file(testPath); + testPath = fileSystem.path.join(testDirectory, '${testName}_test.dart'); + final File testFile = fileSystem.file(testPath); if (!testFile.existsSync()) { fail('missing test file: $testFile'); } } final List args = [ - globals.fs.path.absolute(globals.fs.path.join('bin', 'flutter_tools.dart')), 'test', '--no-color', '--no-version-check', + '--no-pub', ...extraArguments, testPath, ]; - while (_testExclusionLock != null) { - await _testExclusionLock; - } - - final Completer testExclusionCompleter = Completer(); - _testExclusionLock = testExclusionCompleter.future; - try { - return await Process.run( - globals.artifacts.getArtifactPath(Artifact.engineDartBinary), - args, - workingDirectory: workingDirectory, - stdoutEncoding: utf8, - stderrEncoding: utf8, - ); - } finally { - _testExclusionLock = null; - testExclusionCompleter.complete(); - } + return Process.run( + flutterBin, // Uses the precompiled flutter tool for faster tests, + args, + workingDirectory: workingDirectory, + stdoutEncoding: utf8, + stderrEncoding: utf8, + ); }