mirror of
https://github.com/flutter/packages.git
synced 2025-06-17 02:48:43 +08:00
[flutter_plugin_tools] Support non-plugin packages for drive-examples
(#5468)
This commit is contained in:
@ -1,3 +1,8 @@
|
||||
## NEXT
|
||||
|
||||
- `drive-examples` now supports non-plugin packages.
|
||||
- Commands that iterate over examples now include non-Flutter example packages.
|
||||
|
||||
## 0.8.4
|
||||
|
||||
- `readme-check` now validates that there's a info tag on code blocks to
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
import 'package:colorize/colorize.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
/// The signature for a print handler for commands that allow overriding the
|
||||
/// print destination.
|
||||
@ -31,26 +30,14 @@ const String platformWindows = 'windows';
|
||||
/// Key for enable experiment.
|
||||
const String kEnableExperiment = 'enable-experiment';
|
||||
|
||||
/// Returns whether the given directory contains a Flutter package.
|
||||
bool isFlutterPackage(FileSystemEntity entity) {
|
||||
/// Returns whether the given directory is a Dart package.
|
||||
bool isPackage(FileSystemEntity entity) {
|
||||
if (entity is! Directory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final File pubspecFile = entity.childFile('pubspec.yaml');
|
||||
final YamlMap pubspecYaml =
|
||||
loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
|
||||
final YamlMap? dependencies = pubspecYaml['dependencies'] as YamlMap?;
|
||||
if (dependencies == null) {
|
||||
return false;
|
||||
}
|
||||
return dependencies.containsKey('flutter');
|
||||
} on FileSystemException {
|
||||
return false;
|
||||
} on YamlException {
|
||||
return false;
|
||||
}
|
||||
// Per https://dart.dev/guides/libraries/create-library-packages#what-makes-a-library-package
|
||||
return entity.childFile('pubspec.yaml').existsSync() &&
|
||||
entity.childDirectory('lib').existsSync();
|
||||
}
|
||||
|
||||
/// Prints `successMessage` in green.
|
||||
|
@ -10,7 +10,6 @@ import 'package:git/git.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'core.dart';
|
||||
import 'plugin_command.dart';
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/repository_package.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
@ -111,13 +110,8 @@ YamlMap? _readPlatformPubspecSectionForPlugin(
|
||||
/// section from [plugin]'s pubspec.yaml, or null if either it is not present,
|
||||
/// or the pubspec couldn't be read.
|
||||
YamlMap? _readPluginPubspecSection(RepositoryPackage package) {
|
||||
final File pubspecFile = package.pubspecFile;
|
||||
if (!pubspecFile.existsSync()) {
|
||||
return null;
|
||||
}
|
||||
final YamlMap pubspecYaml =
|
||||
loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
|
||||
final YamlMap? flutterSection = pubspecYaml['flutter'] as YamlMap?;
|
||||
final Pubspec pubspec = package.parsePubspec();
|
||||
final Map<String, dynamic>? flutterSection = pubspec.flutter;
|
||||
if (flutterSection == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'core.dart';
|
||||
|
||||
export 'package:pubspec_parse/pubspec_parse.dart' show Pubspec;
|
||||
|
||||
/// A package in the repository.
|
||||
//
|
||||
// TODO(stuartmorgan): Add more package-related info here, such as an on-demand
|
||||
@ -59,6 +61,12 @@ class RepositoryPackage {
|
||||
/// Caches for future use.
|
||||
Pubspec parsePubspec() => _parsedPubspec;
|
||||
|
||||
/// Returns true if the package depends on Flutter.
|
||||
bool requiresFlutter() {
|
||||
final Pubspec pubspec = parsePubspec();
|
||||
return pubspec.dependencies.containsKey('flutter');
|
||||
}
|
||||
|
||||
/// True if this appears to be a federated plugin package, according to
|
||||
/// repository conventions.
|
||||
bool get isFederated =>
|
||||
@ -91,7 +99,7 @@ class RepositoryPackage {
|
||||
if (!exampleDirectory.existsSync()) {
|
||||
return <RepositoryPackage>[];
|
||||
}
|
||||
if (isFlutterPackage(exampleDirectory)) {
|
||||
if (isPackage(exampleDirectory)) {
|
||||
return <RepositoryPackage>[RepositoryPackage(exampleDirectory)];
|
||||
}
|
||||
// Only look at the subdirectories of the example directory if the example
|
||||
@ -99,8 +107,8 @@ class RepositoryPackage {
|
||||
// example directory for other Dart packages.
|
||||
return exampleDirectory
|
||||
.listSync()
|
||||
.where((FileSystemEntity entity) => isFlutterPackage(entity))
|
||||
// isFlutterPackage guarantees that the cast to Directory is safe.
|
||||
.where((FileSystemEntity entity) => isPackage(entity))
|
||||
// isPackage guarantees that the cast to Directory is safe.
|
||||
.map((FileSystemEntity entity) =>
|
||||
RepositoryPackage(entity as Directory));
|
||||
}
|
||||
|
@ -123,6 +123,8 @@ class DriveExamplesCommand extends PackageLoopingCommand {
|
||||
|
||||
@override
|
||||
Future<PackageResult> runForPackage(RepositoryPackage package) async {
|
||||
final bool isPlugin = isFlutterPlugin(package);
|
||||
|
||||
if (package.isPlatformInterface &&
|
||||
!package.getSingleExampleDeprecated().directory.existsSync()) {
|
||||
// Platform interface packages generally aren't intended to have
|
||||
@ -131,23 +133,23 @@ class DriveExamplesCommand extends PackageLoopingCommand {
|
||||
'Platform interfaces are not expected to have integration tests.');
|
||||
}
|
||||
|
||||
final List<String> deviceFlags = <String>[];
|
||||
for (final MapEntry<String, List<String>> entry
|
||||
in _targetDeviceFlags.entries) {
|
||||
final String platform = entry.key;
|
||||
if (pluginSupportsPlatform(platform, package)) {
|
||||
deviceFlags.addAll(entry.value);
|
||||
} else {
|
||||
print('Skipping unsupported platform ${entry.key}...');
|
||||
// For plugin packages, skip if the plugin itself doesn't support any
|
||||
// requested platform(s).
|
||||
if (isPlugin) {
|
||||
final Iterable<String> requestedPlatforms = _targetDeviceFlags.keys;
|
||||
final Iterable<String> unsupportedPlatforms = requestedPlatforms.where(
|
||||
(String platform) => !pluginSupportsPlatform(platform, package));
|
||||
for (final String platform in unsupportedPlatforms) {
|
||||
print('Skipping unsupported platform $platform...');
|
||||
}
|
||||
}
|
||||
// If there is no supported target platform, skip the plugin.
|
||||
if (deviceFlags.isEmpty) {
|
||||
if (unsupportedPlatforms.length == requestedPlatforms.length) {
|
||||
return PackageResult.skip(
|
||||
'${package.displayName} does not support any requested platform.');
|
||||
}
|
||||
}
|
||||
|
||||
int examplesFound = 0;
|
||||
int supportedExamplesFound = 0;
|
||||
bool testsRan = false;
|
||||
final List<String> errors = <String>[];
|
||||
for (final RepositoryPackage example in package.getExamples()) {
|
||||
@ -155,6 +157,15 @@ class DriveExamplesCommand extends PackageLoopingCommand {
|
||||
final String exampleName =
|
||||
getRelativePosixPath(example.directory, from: packagesDir);
|
||||
|
||||
// Skip examples that don't support any requested platform(s).
|
||||
final List<String> deviceFlags = _deviceFlagsForExample(example);
|
||||
if (deviceFlags.isEmpty) {
|
||||
print(
|
||||
'Skipping $exampleName; does not support any requested platforms.');
|
||||
continue;
|
||||
}
|
||||
++supportedExamplesFound;
|
||||
|
||||
final List<File> drivers = await _getDrivers(example);
|
||||
if (drivers.isEmpty) {
|
||||
print('No driver tests found for $exampleName');
|
||||
@ -195,14 +206,41 @@ class DriveExamplesCommand extends PackageLoopingCommand {
|
||||
}
|
||||
}
|
||||
if (!testsRan) {
|
||||
printError('No driver tests were run ($examplesFound example(s) found).');
|
||||
// It is an error for a plugin not to have integration tests, because that
|
||||
// is the only way to test the method channel communication.
|
||||
if (isPlugin) {
|
||||
printError(
|
||||
'No driver tests were run ($examplesFound example(s) found).');
|
||||
errors.add('No tests ran (use --exclude if this is intentional).');
|
||||
} else {
|
||||
return PackageResult.skip(supportedExamplesFound == 0
|
||||
? 'No example supports requested platform(s).'
|
||||
: 'No example is configured for driver tests.');
|
||||
}
|
||||
}
|
||||
return errors.isEmpty
|
||||
? PackageResult.success()
|
||||
: PackageResult.fail(errors);
|
||||
}
|
||||
|
||||
/// Returns the device flags for the intersection of the requested platforms
|
||||
/// and the platforms supported by [example].
|
||||
List<String> _deviceFlagsForExample(RepositoryPackage example) {
|
||||
final List<String> deviceFlags = <String>[];
|
||||
for (final MapEntry<String, List<String>> entry
|
||||
in _targetDeviceFlags.entries) {
|
||||
final String platform = entry.key;
|
||||
if (example.directory.childDirectory(platform).existsSync()) {
|
||||
deviceFlags.addAll(entry.value);
|
||||
} else {
|
||||
final String exampleName =
|
||||
getRelativePosixPath(example.directory, from: packagesDir);
|
||||
print('Skipping unsupported platform $platform for $exampleName');
|
||||
}
|
||||
}
|
||||
return deviceFlags;
|
||||
}
|
||||
|
||||
Future<List<String>> _getDevicesForPlatform(String platform) async {
|
||||
final List<String> deviceIds = <String>[];
|
||||
|
||||
|
@ -8,7 +8,6 @@ import 'package:git/git.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/file_utils.dart';
|
||||
|
@ -3,15 +3,14 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/repository_package.dart';
|
||||
import 'package:git/git.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
import 'common/plugin_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
const int _exitPackageNotFound = 3;
|
||||
const int _exitCannotUpdatePubspec = 4;
|
||||
|
@ -10,7 +10,6 @@ import 'package:file/file.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
|
@ -13,7 +13,6 @@ import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:git/git.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:git/git.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
|
@ -43,7 +43,7 @@ class TestCommand extends PackageLoopingCommand {
|
||||
}
|
||||
|
||||
bool passed;
|
||||
if (isFlutterPackage(package.directory)) {
|
||||
if (package.requiresFlutter()) {
|
||||
passed = await _runFlutterTests(package);
|
||||
} else {
|
||||
passed = await _runDartTests(package);
|
||||
|
@ -9,7 +9,6 @@ import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/repository_package.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../util.dart';
|
||||
@ -97,7 +96,7 @@ void main() {
|
||||
});
|
||||
|
||||
group('getExamples', () {
|
||||
test('handles a single example', () async {
|
||||
test('handles a single Flutter example', () async {
|
||||
final Directory plugin = createFakePlugin('a_plugin', packagesDir);
|
||||
|
||||
final List<RepositoryPackage> examples =
|
||||
@ -107,7 +106,7 @@ void main() {
|
||||
expect(examples[0].path, plugin.childDirectory('example').path);
|
||||
});
|
||||
|
||||
test('handles multiple examples', () async {
|
||||
test('handles multiple Flutter examples', () async {
|
||||
final Directory plugin = createFakePlugin('a_plugin', packagesDir,
|
||||
examples: <String>['example1', 'example2']);
|
||||
|
||||
@ -120,6 +119,30 @@ void main() {
|
||||
expect(examples[1].path,
|
||||
plugin.childDirectory('example').childDirectory('example2').path);
|
||||
});
|
||||
|
||||
test('handles a single non-Flutter example', () async {
|
||||
final Directory package = createFakePackage('a_package', packagesDir);
|
||||
|
||||
final List<RepositoryPackage> examples =
|
||||
RepositoryPackage(package).getExamples().toList();
|
||||
|
||||
expect(examples.length, 1);
|
||||
expect(examples[0].path, package.childDirectory('example').path);
|
||||
});
|
||||
|
||||
test('handles multiple non-Flutter examples', () async {
|
||||
final Directory package = createFakePackage('a_package', packagesDir,
|
||||
examples: <String>['example1', 'example2']);
|
||||
|
||||
final List<RepositoryPackage> examples =
|
||||
RepositoryPackage(package).getExamples().toList();
|
||||
|
||||
expect(examples.length, 2);
|
||||
expect(examples[0].path,
|
||||
package.childDirectory('example').childDirectory('example1').path);
|
||||
expect(examples[1].path,
|
||||
package.childDirectory('example').childDirectory('example2').path);
|
||||
});
|
||||
});
|
||||
|
||||
group('federated plugin queries', () {
|
||||
@ -179,4 +202,18 @@ void main() {
|
||||
expect(pubspec.name, 'a_plugin');
|
||||
});
|
||||
});
|
||||
|
||||
group('requiresFlutter', () {
|
||||
test('returns true for Flutter package', () async {
|
||||
final Directory package =
|
||||
createFakePackage('a_package', packagesDir, isFlutter: true);
|
||||
expect(RepositoryPackage(package).requiresFlutter(), true);
|
||||
});
|
||||
|
||||
test('returns false for non-Flutter package', () async {
|
||||
final Directory package =
|
||||
createFakePackage('a_package', packagesDir, isFlutter: false);
|
||||
expect(RepositoryPackage(package).requiresFlutter(), false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import 'package:file/local.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/repository_package.dart';
|
||||
import 'package:flutter_plugin_tools/src/create_all_plugins_app_command.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'util.dart';
|
||||
|
@ -128,6 +128,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/integration_test.dart',
|
||||
'example/integration_test/foo_test.dart',
|
||||
'example/ios/ios.m',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -193,6 +194,8 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/android/android.java',
|
||||
'example/ios/ios.m',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -243,6 +246,8 @@ void main() {
|
||||
packagesDir,
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/android/android.java',
|
||||
'example/ios/ios.m',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -276,6 +281,8 @@ void main() {
|
||||
packagesDir,
|
||||
extraFiles: <String>[
|
||||
'example/lib/main.dart',
|
||||
'example/android/android.java',
|
||||
'example/ios/ios.m',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -312,6 +319,8 @@ void main() {
|
||||
'example/integration_test/bar_test.dart',
|
||||
'example/integration_test/foo_test.dart',
|
||||
'example/integration_test/ignore_me.dart',
|
||||
'example/android/android.java',
|
||||
'example/ios/ios.m',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -398,6 +407,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/linux/linux.cc',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformLinux: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -542,6 +552,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/web/index.html',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -591,6 +602,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/web/index.html',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -668,6 +680,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/windows/windows.cpp',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformWindows: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -715,6 +728,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/android/android.java',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -853,6 +867,8 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/plugin_test.dart',
|
||||
'example/test_driver/plugin.dart',
|
||||
'example/android/android.java',
|
||||
'example/ios/ios.m',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -927,6 +943,7 @@ void main() {
|
||||
extraFiles: <String>[
|
||||
'example/integration_test/bar_test.dart',
|
||||
'example/integration_test/foo_test.dart',
|
||||
'example/web/index.html',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -959,6 +976,7 @@ void main() {
|
||||
packagesDir,
|
||||
extraFiles: <String>[
|
||||
'example/test_driver/integration_test.dart',
|
||||
'example/web/index.html',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -995,6 +1013,7 @@ void main() {
|
||||
'example/test_driver/integration_test.dart',
|
||||
'example/integration_test/bar_test.dart',
|
||||
'example/integration_test/foo_test.dart',
|
||||
'example/macos/macos.swift',
|
||||
],
|
||||
platformSupport: <String, PlatformDetails>{
|
||||
platformMacOS: const PlatformDetails(PlatformSupport.inline),
|
||||
@ -1060,5 +1079,147 @@ void main() {
|
||||
pluginExampleDirectory.path),
|
||||
]));
|
||||
});
|
||||
|
||||
group('packages', () {
|
||||
test('can be driven', () async {
|
||||
final Directory package =
|
||||
createFakePackage('a_package', packagesDir, extraFiles: <String>[
|
||||
'example/integration_test/foo_test.dart',
|
||||
'example/test_driver/integration_test.dart',
|
||||
'example/web/index.html',
|
||||
]);
|
||||
final Directory exampleDirectory = package.childDirectory('example');
|
||||
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
'drive-examples',
|
||||
'--web',
|
||||
]);
|
||||
|
||||
expect(
|
||||
output,
|
||||
containsAllInOrder(<Matcher>[
|
||||
contains('Running for a_package'),
|
||||
contains('No issues found!'),
|
||||
]),
|
||||
);
|
||||
|
||||
expect(
|
||||
processRunner.recordedCalls,
|
||||
orderedEquals(<ProcessCall>[
|
||||
ProcessCall(
|
||||
getFlutterCommand(mockPlatform),
|
||||
const <String>[
|
||||
'drive',
|
||||
'-d',
|
||||
'web-server',
|
||||
'--web-port=7357',
|
||||
'--browser-name=chrome',
|
||||
'--driver',
|
||||
'test_driver/integration_test.dart',
|
||||
'--target',
|
||||
'integration_test/foo_test.dart'
|
||||
],
|
||||
exampleDirectory.path),
|
||||
]));
|
||||
});
|
||||
|
||||
test('are skipped when example does not support platform', () async {
|
||||
createFakePackage('a_package', packagesDir,
|
||||
isFlutter: true,
|
||||
extraFiles: <String>[
|
||||
'example/integration_test/foo_test.dart',
|
||||
'example/test_driver/integration_test.dart',
|
||||
]);
|
||||
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
'drive-examples',
|
||||
'--web',
|
||||
]);
|
||||
|
||||
expect(
|
||||
output,
|
||||
containsAllInOrder(<Matcher>[
|
||||
contains('Running for a_package'),
|
||||
contains('Skipping a_package/example; does not support any '
|
||||
'requested platforms'),
|
||||
contains('SKIPPING: No example supports requested platform(s).'),
|
||||
]),
|
||||
);
|
||||
|
||||
expect(processRunner.recordedCalls.isEmpty, true);
|
||||
});
|
||||
|
||||
test('drive only supported examples if there is more than one', () async {
|
||||
final Directory package = createFakePackage('a_package', packagesDir,
|
||||
isFlutter: true,
|
||||
examples: <String>[
|
||||
'with_web',
|
||||
'without_web'
|
||||
],
|
||||
extraFiles: <String>[
|
||||
'example/with_web/integration_test/foo_test.dart',
|
||||
'example/with_web/test_driver/integration_test.dart',
|
||||
'example/with_web/web/index.html',
|
||||
'example/without_web/integration_test/foo_test.dart',
|
||||
'example/without_web/test_driver/integration_test.dart',
|
||||
]);
|
||||
final Directory supportedExampleDirectory =
|
||||
package.childDirectory('example').childDirectory('with_web');
|
||||
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
'drive-examples',
|
||||
'--web',
|
||||
]);
|
||||
|
||||
expect(
|
||||
output,
|
||||
containsAllInOrder(<Matcher>[
|
||||
contains('Running for a_package'),
|
||||
contains(
|
||||
'Skipping a_package/example/without_web; does not support any requested platforms.'),
|
||||
contains('No issues found!'),
|
||||
]),
|
||||
);
|
||||
|
||||
expect(
|
||||
processRunner.recordedCalls,
|
||||
orderedEquals(<ProcessCall>[
|
||||
ProcessCall(
|
||||
getFlutterCommand(mockPlatform),
|
||||
const <String>[
|
||||
'drive',
|
||||
'-d',
|
||||
'web-server',
|
||||
'--web-port=7357',
|
||||
'--browser-name=chrome',
|
||||
'--driver',
|
||||
'test_driver/integration_test.dart',
|
||||
'--target',
|
||||
'integration_test/foo_test.dart'
|
||||
],
|
||||
supportedExampleDirectory.path),
|
||||
]));
|
||||
});
|
||||
|
||||
test('are skipped when there is no integration testing', () async {
|
||||
createFakePackage('a_package', packagesDir,
|
||||
isFlutter: true, extraFiles: <String>['example/web/index.html']);
|
||||
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
'drive-examples',
|
||||
'--web',
|
||||
]);
|
||||
|
||||
expect(
|
||||
output,
|
||||
containsAllInOrder(<Matcher>[
|
||||
contains('Running for a_package'),
|
||||
contains('SKIPPING: No example is configured for driver tests.'),
|
||||
]),
|
||||
);
|
||||
|
||||
expect(processRunner.recordedCalls.isEmpty, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import 'mocks.dart';
|
||||
import 'util.dart';
|
||||
|
||||
void main() {
|
||||
group('$ListCommand', () {
|
||||
group('ListCommand', () {
|
||||
late FileSystem fileSystem;
|
||||
late MockPlatform mockPlatform;
|
||||
late Directory packagesDir;
|
||||
|
@ -155,6 +155,21 @@ ${_flutterSection(isPlugin: true)}
|
||||
${_dependenciesSection()}
|
||||
${_devDependenciesSection()}
|
||||
${_falseSecretsSection()}
|
||||
''');
|
||||
|
||||
pluginDirectory
|
||||
.childDirectory('example')
|
||||
.childFile('pubspec.yaml')
|
||||
.writeAsStringSync('''
|
||||
${_headerSection(
|
||||
'plugin_example',
|
||||
publishable: false,
|
||||
includeRepository: false,
|
||||
includeIssueTracker: false,
|
||||
)}
|
||||
${_environmentSection()}
|
||||
${_dependenciesSection()}
|
||||
${_flutterSection()}
|
||||
''');
|
||||
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
@ -172,15 +187,31 @@ ${_falseSecretsSection()}
|
||||
});
|
||||
|
||||
test('passes for a Flutter package following conventions', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory packageDirectory =
|
||||
createFakePackage('a_package', packagesDir);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin')}
|
||||
packageDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('a_package')}
|
||||
${_environmentSection()}
|
||||
${_dependenciesSection()}
|
||||
${_devDependenciesSection()}
|
||||
${_flutterSection()}
|
||||
${_falseSecretsSection()}
|
||||
''');
|
||||
|
||||
packageDirectory
|
||||
.childDirectory('example')
|
||||
.childFile('pubspec.yaml')
|
||||
.writeAsStringSync('''
|
||||
${_headerSection(
|
||||
'a_package',
|
||||
publishable: false,
|
||||
includeRepository: false,
|
||||
includeIssueTracker: false,
|
||||
)}
|
||||
${_environmentSection()}
|
||||
${_dependenciesSection()}
|
||||
${_flutterSection()}
|
||||
''');
|
||||
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
@ -190,8 +221,8 @@ ${_falseSecretsSection()}
|
||||
expect(
|
||||
output,
|
||||
containsAllInOrder(<Matcher>[
|
||||
contains('Running for plugin...'),
|
||||
contains('Running for plugin/example...'),
|
||||
contains('Running for a_package...'),
|
||||
contains('Running for a_package/example...'),
|
||||
contains('No issues found!'),
|
||||
]),
|
||||
);
|
||||
@ -221,7 +252,8 @@ ${_dependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when homepage is included', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, includeHomepage: true)}
|
||||
@ -248,7 +280,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when repository is missing', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, includeRepository: false)}
|
||||
@ -274,7 +307,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when homepage is given instead of repository', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, includeHomepage: true, includeRepository: false)}
|
||||
@ -301,7 +335,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when repository is incorrect', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, repositoryPackagesDirRelativePath: 'different_plugin')}
|
||||
@ -327,7 +362,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when issue tracker is missing', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, includeIssueTracker: false)}
|
||||
@ -353,8 +389,9 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when description is too short', () async {
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('a_plugin', packagesDir.childDirectory('a_plugin'));
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'a_plugin', packagesDir.childDirectory('a_plugin'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, description: 'Too short')}
|
||||
@ -383,7 +420,8 @@ ${_devDependenciesSection()}
|
||||
test(
|
||||
'allows short descriptions for non-app-facing parts of federated plugins',
|
||||
() async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true, description: 'Too short')}
|
||||
@ -410,7 +448,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when description is too long', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
const String description = 'This description is too long. It just goes '
|
||||
'on and on and on and on and on. pub.dev will down-score it because '
|
||||
@ -442,7 +481,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when environment section is out of order', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true)}
|
||||
@ -469,7 +509,8 @@ ${_environmentSection()}
|
||||
});
|
||||
|
||||
test('fails when flutter section is out of order', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true)}
|
||||
@ -496,7 +537,8 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when dependencies section is out of order', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true)}
|
||||
@ -550,7 +592,8 @@ ${_dependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when false_secrets section is out of order', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin', isPlugin: true)}
|
||||
@ -580,7 +623,8 @@ ${_devDependenciesSection()}
|
||||
test('fails when an implemenation package is missing "implements"',
|
||||
() async {
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'));
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin_a_foo', isPlugin: true)}
|
||||
@ -608,7 +652,8 @@ ${_devDependenciesSection()}
|
||||
test('fails when an implemenation package has the wrong "implements"',
|
||||
() async {
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'));
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('plugin_a_foo', isPlugin: true)}
|
||||
@ -636,7 +681,8 @@ ${_devDependenciesSection()}
|
||||
|
||||
test('passes for a correct implemenation package', () async {
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'));
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection(
|
||||
@ -663,8 +709,9 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('fails when a "default_package" looks incorrect', () async {
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin_a', packagesDir.childDirectory('plugin_a'));
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection(
|
||||
@ -702,8 +749,9 @@ ${_devDependenciesSection()}
|
||||
test(
|
||||
'fails when a "default_package" does not have a corresponding dependency',
|
||||
() async {
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin_a', packagesDir.childDirectory('plugin_a'));
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection(
|
||||
@ -739,8 +787,9 @@ ${_devDependenciesSection()}
|
||||
});
|
||||
|
||||
test('passes for an app-facing package without "implements"', () async {
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin_a', packagesDir.childDirectory('plugin_a'));
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection(
|
||||
@ -769,8 +818,8 @@ ${_devDependenciesSection()}
|
||||
test('passes for a platform interface package without "implements"',
|
||||
() async {
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a_platform_interface',
|
||||
packagesDir.childDirectory('plugin_a'));
|
||||
'plugin_a_platform_interface', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection(
|
||||
@ -799,7 +848,8 @@ ${_devDependenciesSection()}
|
||||
|
||||
test('validates some properties even for unpublished packages', () async {
|
||||
final Directory pluginDirectory = createFakePlugin(
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'));
|
||||
'plugin_a_foo', packagesDir.childDirectory('plugin_a'),
|
||||
examples: <String>[]);
|
||||
|
||||
// Environment section is in the wrong location.
|
||||
// Missing 'implements'.
|
||||
@ -829,7 +879,8 @@ ${_environmentSection()}
|
||||
});
|
||||
|
||||
test('ignores some checks for unpublished packages', () async {
|
||||
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
|
||||
final Directory pluginDirectory =
|
||||
createFakePlugin('plugin', packagesDir, examples: <String>[]);
|
||||
|
||||
// Missing metadata that is only useful for published packages, such as
|
||||
// repository and issue tracker.
|
||||
@ -886,7 +937,7 @@ ${_devDependenciesSection()}
|
||||
|
||||
test('repository check works', () async {
|
||||
final Directory packageDirectory =
|
||||
createFakePackage('package', packagesDir);
|
||||
createFakePackage('package', packagesDir, examples: <String>[]);
|
||||
|
||||
packageDirectory.childFile('pubspec.yaml').writeAsStringSync('''
|
||||
${_headerSection('package')}
|
||||
|
@ -107,6 +107,12 @@ Directory createFakePlugin(
|
||||
///
|
||||
/// [extraFiles] is an optional list of package-relative paths, using unix-style
|
||||
/// separators, of extra files to create in the package.
|
||||
///
|
||||
/// If [includeCommonFiles] is true, common but non-critical files like
|
||||
/// CHANGELOG.md and AUTHORS will be included.
|
||||
///
|
||||
/// If non-null, [directoryName] will be used for the directory instead of
|
||||
/// [name].
|
||||
// TODO(stuartmorgan): Convert the return to a RepositoryPackage.
|
||||
Directory createFakePackage(
|
||||
String name,
|
||||
@ -116,37 +122,43 @@ Directory createFakePackage(
|
||||
bool isFlutter = false,
|
||||
String? version = '0.0.1',
|
||||
String flutterConstraint = '>=2.5.0',
|
||||
bool includeCommonFiles = true,
|
||||
String? directoryName,
|
||||
String? publishTo,
|
||||
}) {
|
||||
final Directory packageDirectory = parentDirectory.childDirectory(name);
|
||||
final Directory packageDirectory =
|
||||
parentDirectory.childDirectory(directoryName ?? name);
|
||||
packageDirectory.createSync(recursive: true);
|
||||
|
||||
packageDirectory.childDirectory('lib').createSync();
|
||||
createFakePubspec(packageDirectory,
|
||||
name: name,
|
||||
isFlutter: isFlutter,
|
||||
version: version,
|
||||
flutterConstraint: flutterConstraint);
|
||||
if (includeCommonFiles) {
|
||||
createFakeCHANGELOG(packageDirectory, '''
|
||||
## $version
|
||||
* Some changes.
|
||||
''');
|
||||
createFakeAuthors(packageDirectory);
|
||||
}
|
||||
|
||||
if (examples.length == 1) {
|
||||
final Directory exampleDir = packageDirectory.childDirectory(examples.first)
|
||||
..createSync();
|
||||
createFakePubspec(exampleDir,
|
||||
name: '${name}_example',
|
||||
createFakePackage('${name}_example', packageDirectory,
|
||||
directoryName: examples.first,
|
||||
examples: <String>[],
|
||||
includeCommonFiles: false,
|
||||
isFlutter: isFlutter,
|
||||
publishTo: 'none',
|
||||
flutterConstraint: flutterConstraint);
|
||||
} else if (examples.isNotEmpty) {
|
||||
final Directory exampleDir = packageDirectory.childDirectory('example')
|
||||
..createSync();
|
||||
for (final String example in examples) {
|
||||
final Directory currentExample = exampleDir.childDirectory(example)
|
||||
..createSync();
|
||||
createFakePubspec(currentExample,
|
||||
name: example,
|
||||
final Directory examplesDirectory =
|
||||
packageDirectory.childDirectory('example')..createSync();
|
||||
for (final String exampleName in examples) {
|
||||
createFakePackage(exampleName, examplesDirectory,
|
||||
examples: <String>[],
|
||||
includeCommonFiles: false,
|
||||
isFlutter: isFlutter,
|
||||
publishTo: 'none',
|
||||
flutterConstraint: flutterConstraint);
|
||||
@ -179,7 +191,7 @@ void createFakePubspec(
|
||||
bool isPlugin = false,
|
||||
Map<String, PlatformDetails> platformSupport =
|
||||
const <String, PlatformDetails>{},
|
||||
String publishTo = 'http://no_pub_server.com',
|
||||
String? publishTo,
|
||||
String? version,
|
||||
String dartConstraint = '>=2.0.0 <3.0.0',
|
||||
String flutterConstraint = '>=2.5.0',
|
||||
@ -219,9 +231,16 @@ flutter:
|
||||
}
|
||||
}
|
||||
|
||||
String yaml = '''
|
||||
// Default to a fake server to avoid ever accidentally publishing something
|
||||
// from a test. Does not use 'none' since that changes the behavior of some
|
||||
// commands.
|
||||
final String publishToSection =
|
||||
'publish_to: ${publishTo ?? 'http://no_pub_server.com'}';
|
||||
|
||||
final String yaml = '''
|
||||
name: $name
|
||||
${(version != null) ? 'version: $version' : ''}
|
||||
$publishToSection
|
||||
|
||||
$environmentSection
|
||||
|
||||
@ -230,11 +249,6 @@ $dependenciesSection
|
||||
$pluginSection
|
||||
''';
|
||||
|
||||
if (publishTo.isNotEmpty) {
|
||||
yaml += '''
|
||||
publish_to: $publishTo # Hardcoded safeguard to prevent this from somehow being published by a broken test.
|
||||
''';
|
||||
}
|
||||
parent.childFile('pubspec.yaml').createSync();
|
||||
parent.childFile('pubspec.yaml').writeAsStringSync(yaml);
|
||||
}
|
||||
|
Reference in New Issue
Block a user