diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index 0539e0c649..03482f838d 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -779,6 +779,8 @@ const String _dartPluginRegistryTemplate = ''' // Generated file. Do not edit. // +// ignore_for_file: lines_longer_than_80_chars + {{#plugins}} import 'package:{{name}}/{{file}}'; {{/plugins}} diff --git a/packages/flutter_tools/test/integration.shard/README.md b/packages/flutter_tools/test/integration.shard/README.md index ce166d10e2..d4875dbf97 100644 --- a/packages/flutter_tools/test/integration.shard/README.md +++ b/packages/flutter_tools/test/integration.shard/README.md @@ -10,8 +10,13 @@ Use this command to run (from the `flutter_tools` directory): ../../bin/cache/dart-sdk/bin/pub run test test/integration.shard ``` +You need to have downloaded the Dart SDK in your Flutter clone for this +to work. Running `../../bin/flutter` will automatically download it. + +## Coverage exclusion + These tests are expensive to run and do not give meaningful coverage -information for the flutter tool (since they are black-box tests that +information for the `flutter` tool (since they are black-box tests that run the tool as a subprocess, rather than being unit tests). For this reason, they are in a separate shard when running on continuous integration and are not run when calculating coverage. diff --git a/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart b/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart new file mode 100644 index 0000000000..54b3307886 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart @@ -0,0 +1,243 @@ +// 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:args/command_runner.dart'; +import 'package:file_testing/file_testing.dart'; +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/commands/create.dart'; +import 'package:flutter_tools/src/dart/pub.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; + +import '../src/common.dart'; +import '../src/context.dart'; +import '../src/testbed.dart'; + +void main() { + Directory tempDir; + Directory projectDir; + + setUpAll(() async { + Cache.disableLocking(); + await _ensureFlutterToolsSnapshot(); + }); + + setUp(() { + tempDir = globals.fs.systemTempDirectory + .createTempSync('flutter_tools_generated_plugin_registrant_test.'); + projectDir = tempDir.childDirectory('flutter_project'); + }); + + tearDown(() { + tryToDelete(tempDir); + }); + + tearDownAll(() async { + await _restoreFlutterToolsSnapshot(); + }); + + testUsingContext('generated plugin registrant passes analysis', () async { + await _createProject(projectDir, []); + // We need to add a dependency with web support to trigger + // the generated_plugin_registrant generation. + await _addDependency(projectDir, 'shared_preferences', + version: '^0.5.12+4'); + await _analyzeProject(projectDir); + + expect( + projectDir.childFile('lib/generated_plugin_registrant.dart'), + exists, + ); + }, overrides: { + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); + + testUsingContext( + 'generated plugin registrant ignores lines longer than 80 chars', + () async { + await _createProject(projectDir, []); + await _addAnalysisOptions( + projectDir, ['lines_longer_than_80_chars']); + await _createProject(tempDir.childDirectory('test_plugin'), [ + '--template=plugin', + '--platforms=web', + '--project-name', + 'test_web_plugin_with_a_purposefully_extremely_long_package_name', + ]); + // The line for the test web plugin (` TestWebPluginWithAPurposefullyExtremelyLongPackageNameWeb.registerWith(registrar);`) + // exceeds 80 chars. + // With the above lint rule added, we want to ensure that the `generated_plugin_registrant.dart` + // file does not fail analysis (this is a regression test - an ignore was + // added to cover this case). + await _addDependency( + projectDir, + 'test_web_plugin_with_a_purposefully_extremely_long_package_name', + path: '../test_plugin', + ); + await _analyzeProject(projectDir); + + expect( + projectDir.childFile('lib/generated_plugin_registrant.dart'), + exists, + ); + }, overrides: { + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); +} + +Future _ensureFlutterToolsSnapshot() async { + final String flutterToolsPath = globals.fs.path.absolute(globals.fs.path.join( + 'bin', + 'flutter_tools.dart', + )); + final String flutterToolsSnapshotPath = globals.fs.path.absolute( + globals.fs.path.join( + '..', + '..', + 'bin', + 'cache', + 'flutter_tools.snapshot', + ), + ); + final String dotPackages = globals.fs.path.absolute(globals.fs.path.join( + '.packages', + )); + + final File snapshotFile = globals.fs.file(flutterToolsSnapshotPath); + if (snapshotFile.existsSync()) { + snapshotFile.renameSync(flutterToolsSnapshotPath + '.bak'); + } + + final List snapshotArgs = [ + '--snapshot=$flutterToolsSnapshotPath', + '--packages=$dotPackages', + flutterToolsPath, + ]; + final ProcessResult snapshotResult = await Process.run( + '../../bin/cache/dart-sdk/bin/dart', + snapshotArgs, + ); + if (snapshotResult.exitCode != 0) { + print(snapshotResult.stdout); + print(snapshotResult.stderr); + } + expect(snapshotResult.exitCode, 0); +} + +Future _restoreFlutterToolsSnapshot() async { + final String flutterToolsSnapshotPath = globals.fs.path.absolute( + globals.fs.path.join( + '..', + '..', + 'bin', + 'cache', + 'flutter_tools.snapshot', + ), + ); + + final File snapshotBackup = + globals.fs.file(flutterToolsSnapshotPath + '.bak'); + if (!snapshotBackup.existsSync()) { + // No backup to restore. + return; + } + + snapshotBackup.renameSync(flutterToolsSnapshotPath); +} + +Future _createProject(Directory dir, List createArgs) async { + Cache.flutterRoot = '../..'; + final CreateCommand command = CreateCommand(); + final CommandRunner runner = createTestCommandRunner(command); + await runner.run([ + 'create', + ...createArgs, + dir.path, + ]); +} + +Future _addDependency( + Directory projectDir, + String package, { + String version, + String path, +}) async { + assert(version != null || path != null, + 'Need to define a source for the package.'); + assert(version == null || path == null, + 'Cannot only load a package from path or from Pub, not both.'); + + final File pubspecYaml = projectDir.childFile('pubspec.yaml'); + expect(pubspecYaml, exists); + + final List lines = await pubspecYaml.readAsLines(); + for (int i = 0; i < lines.length; i++) { + final String line = lines[i]; + if (line.startsWith('dependencies:')) { + lines.insert( + i + 1, + ' $package: ${version ?? '\n' + ' path: $path'}'); + break; + } + } + await pubspecYaml.writeAsString(lines.join('\n')); +} + +Future _addAnalysisOptions( + Directory projectDir, List linterRules) async { + assert(linterRules.isNotEmpty); + + await projectDir.childFile('analysis_options.yaml').writeAsString(''' +linter: + rules: +${linterRules.map((String rule) => ' - $rule').join('\n')} + '''); +} + +Future _analyzeProject(Directory workingDir) async { + final String flutterToolsSnapshotPath = globals.fs.path.absolute( + globals.fs.path.join( + '..', + '..', + 'bin', + 'cache', + 'flutter_tools.snapshot', + ), + ); + + final List args = [ + flutterToolsSnapshotPath, + 'analyze', + ]; + + final ProcessResult exec = await Process.run( + globals.artifacts.getArtifactPath(Artifact.engineDartBinary), + args, + workingDirectory: workingDir.path, + ); + if (exec.exitCode != 0) { + print(exec.stdout); + print(exec.stderr); + } + expect(exec.exitCode, 0); +}