mirror of
https://github.com/flutter/packages.git
synced 2025-08-24 03:18:54 +08:00

Consolidates the code to find all changed file paths into the `PackageLoopingCommand` class that is the base of almost all of the repo tooling commands. This in a preparatory PR for a future change to allow each command to define a list of files or file patterns that definitively *don't* affect that test, so that CI can be smarter about what tests to run (e.g., not running expensive integration tests for README changes). A side effect of this change is that tests of almost all commands now need a mock `GitDir` instance. This would add a lot of copy/pasted boilerplate to the test setup, and there is already too much of that, so instead this refactors common test setup: - Creating a memory file system - Populating it with a packages directory - Creating a RecordingProcessRunner to mock out process calls - Creating a mock GitDir that forwards to a RecordingProcessRunner into a helper method (using records and destructuring to easily return multiple values). While some tests don't need all of these steps, those that don't can easily ignore parts of it, and it will make it much easier to update tests in the future if they need them, and it makes the setup much more consistent which makes it easier to reason about test setup in general. Prep for https://github.com/flutter/flutter/issues/136394
242 lines
8.0 KiB
Dart
242 lines
8.0 KiB
Dart
// Copyright 2013 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 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:pubspec_parse/pubspec_parse.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../util.dart';
|
|
|
|
void main() {
|
|
late Directory packagesDir;
|
|
|
|
setUp(() {
|
|
(:packagesDir, processRunner: _, gitProcessRunner: _, gitDir: _) =
|
|
configureBaseCommandMocks();
|
|
});
|
|
|
|
group('displayName', () {
|
|
test('prints packageDir-relative paths by default', () async {
|
|
expect(
|
|
RepositoryPackage(packagesDir.childDirectory('foo')).displayName,
|
|
'foo',
|
|
);
|
|
expect(
|
|
RepositoryPackage(packagesDir
|
|
.childDirectory('foo')
|
|
.childDirectory('bar')
|
|
.childDirectory('baz'))
|
|
.displayName,
|
|
'foo/bar/baz',
|
|
);
|
|
});
|
|
|
|
test('handles third_party/packages/', () async {
|
|
expect(
|
|
RepositoryPackage(packagesDir.parent
|
|
.childDirectory('third_party')
|
|
.childDirectory('packages')
|
|
.childDirectory('foo')
|
|
.childDirectory('bar')
|
|
.childDirectory('baz'))
|
|
.displayName,
|
|
'foo/bar/baz',
|
|
);
|
|
});
|
|
|
|
test('always uses Posix-style paths', () async {
|
|
final Directory windowsPackagesDir = createPackagesDirectory(
|
|
MemoryFileSystem(style: FileSystemStyle.windows));
|
|
|
|
expect(
|
|
RepositoryPackage(windowsPackagesDir.childDirectory('foo')).displayName,
|
|
'foo',
|
|
);
|
|
expect(
|
|
RepositoryPackage(windowsPackagesDir
|
|
.childDirectory('foo')
|
|
.childDirectory('bar')
|
|
.childDirectory('baz'))
|
|
.displayName,
|
|
'foo/bar/baz',
|
|
);
|
|
});
|
|
|
|
test('elides group name in grouped federated plugin structure', () async {
|
|
expect(
|
|
RepositoryPackage(packagesDir
|
|
.childDirectory('a_plugin')
|
|
.childDirectory('a_plugin_platform_interface'))
|
|
.displayName,
|
|
'a_plugin_platform_interface',
|
|
);
|
|
expect(
|
|
RepositoryPackage(packagesDir
|
|
.childDirectory('a_plugin')
|
|
.childDirectory('a_plugin_platform_web'))
|
|
.displayName,
|
|
'a_plugin_platform_web',
|
|
);
|
|
});
|
|
|
|
// The app-facing package doesn't get elided to avoid potential confusion
|
|
// with the group folder itself.
|
|
test('does not elide group name for app-facing packages', () async {
|
|
expect(
|
|
RepositoryPackage(packagesDir
|
|
.childDirectory('a_plugin')
|
|
.childDirectory('a_plugin'))
|
|
.displayName,
|
|
'a_plugin/a_plugin',
|
|
);
|
|
});
|
|
});
|
|
|
|
group('getExamples', () {
|
|
test('handles a single Flutter example', () async {
|
|
final RepositoryPackage plugin =
|
|
createFakePlugin('a_plugin', packagesDir);
|
|
|
|
final List<RepositoryPackage> examples = plugin.getExamples().toList();
|
|
|
|
expect(examples.length, 1);
|
|
expect(examples[0].isExample, isTrue);
|
|
expect(examples[0].path, getExampleDir(plugin).path);
|
|
});
|
|
|
|
test('handles multiple Flutter examples', () async {
|
|
final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir,
|
|
examples: <String>['example1', 'example2']);
|
|
|
|
final List<RepositoryPackage> examples = plugin.getExamples().toList();
|
|
|
|
expect(examples.length, 2);
|
|
expect(examples[0].isExample, isTrue);
|
|
expect(examples[1].isExample, isTrue);
|
|
expect(examples[0].path,
|
|
getExampleDir(plugin).childDirectory('example1').path);
|
|
expect(examples[1].path,
|
|
getExampleDir(plugin).childDirectory('example2').path);
|
|
});
|
|
|
|
test('handles a single non-Flutter example', () async {
|
|
final RepositoryPackage package =
|
|
createFakePackage('a_package', packagesDir);
|
|
|
|
final List<RepositoryPackage> examples = package.getExamples().toList();
|
|
|
|
expect(examples.length, 1);
|
|
expect(examples[0].isExample, isTrue);
|
|
expect(examples[0].path, getExampleDir(package).path);
|
|
});
|
|
|
|
test('handles multiple non-Flutter examples', () async {
|
|
final RepositoryPackage package = createFakePackage(
|
|
'a_package', packagesDir,
|
|
examples: <String>['example1', 'example2']);
|
|
|
|
final List<RepositoryPackage> examples = package.getExamples().toList();
|
|
|
|
expect(examples.length, 2);
|
|
expect(examples[0].isExample, isTrue);
|
|
expect(examples[1].isExample, isTrue);
|
|
expect(examples[0].path,
|
|
getExampleDir(package).childDirectory('example1').path);
|
|
expect(examples[1].path,
|
|
getExampleDir(package).childDirectory('example2').path);
|
|
});
|
|
});
|
|
|
|
group('federated plugin queries', () {
|
|
test('all return false for a simple plugin', () {
|
|
final RepositoryPackage plugin =
|
|
createFakePlugin('a_plugin', packagesDir);
|
|
expect(plugin.isFederated, false);
|
|
expect(plugin.isAppFacing, false);
|
|
expect(plugin.isPlatformInterface, false);
|
|
expect(plugin.isFederated, false);
|
|
expect(plugin.isExample, isFalse);
|
|
});
|
|
|
|
test('handle app-facing packages', () {
|
|
final RepositoryPackage plugin =
|
|
createFakePlugin('a_plugin', packagesDir.childDirectory('a_plugin'));
|
|
expect(plugin.isFederated, true);
|
|
expect(plugin.isAppFacing, true);
|
|
expect(plugin.isPlatformInterface, false);
|
|
expect(plugin.isPlatformImplementation, false);
|
|
expect(plugin.isExample, isFalse);
|
|
});
|
|
|
|
test('handle platform interface packages', () {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'a_plugin_platform_interface',
|
|
packagesDir.childDirectory('a_plugin'));
|
|
expect(plugin.isFederated, true);
|
|
expect(plugin.isAppFacing, false);
|
|
expect(plugin.isPlatformInterface, true);
|
|
expect(plugin.isPlatformImplementation, false);
|
|
expect(plugin.isExample, isFalse);
|
|
});
|
|
|
|
test('handle platform implementation packages', () {
|
|
// A platform interface can end with anything, not just one of the known
|
|
// platform names, because of cases like webview_flutter_wkwebview.
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'a_plugin_foo', packagesDir.childDirectory('a_plugin'));
|
|
expect(plugin.isFederated, true);
|
|
expect(plugin.isAppFacing, false);
|
|
expect(plugin.isPlatformInterface, false);
|
|
expect(plugin.isPlatformImplementation, true);
|
|
expect(plugin.isExample, isFalse);
|
|
});
|
|
});
|
|
|
|
group('pubspec', () {
|
|
test('file', () async {
|
|
final RepositoryPackage plugin =
|
|
createFakePlugin('a_plugin', packagesDir);
|
|
|
|
final File pubspecFile = plugin.pubspecFile;
|
|
|
|
expect(pubspecFile.path, plugin.directory.childFile('pubspec.yaml').path);
|
|
});
|
|
|
|
test('parsing', () async {
|
|
final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir,
|
|
examples: <String>['example1', 'example2']);
|
|
|
|
final Pubspec pubspec = plugin.parsePubspec();
|
|
|
|
expect(pubspec.name, 'a_plugin');
|
|
});
|
|
});
|
|
|
|
group('requiresFlutter', () {
|
|
test('returns true for Flutter package', () async {
|
|
final RepositoryPackage package =
|
|
createFakePackage('a_package', packagesDir, isFlutter: true);
|
|
expect(package.requiresFlutter(), true);
|
|
});
|
|
|
|
test('returns true for a dev dependency on Flutter', () async {
|
|
final RepositoryPackage package =
|
|
createFakePackage('a_package', packagesDir);
|
|
final File pubspecFile = package.pubspecFile;
|
|
final Pubspec pubspec = package.parsePubspec();
|
|
pubspec.devDependencies['flutter'] = SdkDependency('flutter');
|
|
pubspecFile.writeAsStringSync(pubspec.toString());
|
|
|
|
expect(package.requiresFlutter(), true);
|
|
});
|
|
|
|
test('returns false for non-Flutter package', () async {
|
|
final RepositoryPackage package =
|
|
createFakePackage('a_package', packagesDir);
|
|
expect(package.requiresFlutter(), false);
|
|
});
|
|
});
|
|
}
|