Files
packages/script/tool/test/pubspec_check_command_test.dart
stuartmorgan 356d316717 [flutter_plugin_tools] Add a new base command for looping over packages (#4067)
Most of our commands are generally of the form:
```
  for (each plugin as defined by the tool flags)
    check some things for success or failure
  print a summary all of the failing things
  exit non-zero if anything failed
```

Currently all that logic not consistent, having been at various points copied and pasted around, modified, in some cases rewritten. There's unnecessary boilerplate in each new command, and there's unnecessary variation that makes it harder both to maintain the tool, and to consume the test output:
- There's no standard format for separating each plugin's run to search within a log
- There's no standard format for the summary at the end
- In some cases commands have been written to ToolExit on failure, which means we don't actually get the rest of the runs

This makes a new base class for commands that follow this structure to use, with shared code for all the common bits. This makes it harder to accidentally write new commands incorrectly, easier to maintain the code, and lets us standardize output so that searching within large logs will be easier.

This ports two commands over as a proof of concept to demonstrate that it works; more will be converted in follow-ups.

Related to https://github.com/flutter/flutter/issues/83413
2021-06-22 13:32:03 -07:00

324 lines
9.2 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:args/command_runner.dart';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_plugin_tools/src/common/core.dart';
import 'package:flutter_plugin_tools/src/pubspec_check_command.dart';
import 'package:test/test.dart';
import 'util.dart';
void main() {
group('test pubspec_check_command', () {
late CommandRunner<void> runner;
late RecordingProcessRunner processRunner;
late FileSystem fileSystem;
late Directory packagesDir;
setUp(() {
fileSystem = MemoryFileSystem();
packagesDir = fileSystem.currentDirectory.childDirectory('packages');
createPackagesDirectory(parentDir: packagesDir.parent);
processRunner = RecordingProcessRunner();
final PubspecCheckCommand command =
PubspecCheckCommand(packagesDir, processRunner: processRunner);
runner = CommandRunner<void>(
'pubspec_check_command', 'Test for pubspec_check_command');
runner.addCommand(command);
});
String headerSection(
String name, {
bool isPlugin = false,
bool includeRepository = true,
bool includeHomepage = false,
bool includeIssueTracker = true,
}) {
final String repoLink = 'https://github.com/flutter/'
'${isPlugin ? 'plugins' : 'packages'}/tree/master/packages/$name';
final String issueTrackerLink =
'https://github.com/flutter/flutter/issues?'
'q=is%3Aissue+is%3Aopen+label%3A%22p%3A+$name%22';
return '''
name: $name
${includeRepository ? 'repository: $repoLink' : ''}
${includeHomepage ? 'homepage: $repoLink' : ''}
${includeIssueTracker ? 'issue_tracker: $issueTrackerLink' : ''}
version: 1.0.0
''';
}
String environmentSection() {
return '''
environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.0.0"
''';
}
String flutterSection({bool isPlugin = false}) {
const String pluginEntry = '''
plugin:
platforms:
''';
return '''
flutter:
${isPlugin ? pluginEntry : ''}
''';
}
String dependenciesSection() {
return '''
dependencies:
flutter:
sdk: flutter
''';
}
String devDependenciesSection() {
return '''
dev_dependencies:
flutter_test:
sdk: flutter
''';
}
test('passes for a plugin following conventions', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true)}
${environmentSection()}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
${devDependenciesSection()}
''');
final List<String> output = await runCapturingPrint(runner, <String>[
'pubspec-check',
]);
expect(
output,
containsAllInOrder(<Matcher>[
contains('Running for plugin...'),
contains('Running for plugin/example...'),
contains('No issues found!'),
]),
);
});
test('passes for a Flutter package following conventions', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin')}
${environmentSection()}
${dependenciesSection()}
${devDependenciesSection()}
${flutterSection()}
''');
final List<String> output = await runCapturingPrint(runner, <String>[
'pubspec-check',
]);
expect(
output,
containsAllInOrder(<Matcher>[
contains('Running for plugin...'),
contains('Running for plugin/example...'),
contains('No issues found!'),
]),
);
});
test('passes for a minimal package following conventions', () async {
final Directory packageDirectory = packagesDir.childDirectory('package');
packageDirectory.createSync(recursive: true);
packageDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('package')}
${environmentSection()}
${dependenciesSection()}
''');
final List<String> output = await runCapturingPrint(runner, <String>[
'pubspec-check',
]);
expect(
output,
containsAllInOrder(<Matcher>[
contains('Running for package...'),
contains('No issues found!'),
]),
);
});
test('fails when homepage is included', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true, includeHomepage: true)}
${environmentSection()}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
${devDependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when repository is missing', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true, includeRepository: false)}
${environmentSection()}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
${devDependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when homepage is given instead of repository', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true, includeHomepage: true, includeRepository: false)}
${environmentSection()}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
${devDependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when issue tracker is missing', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true, includeIssueTracker: false)}
${environmentSection()}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
${devDependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when environment section is out of order', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true)}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
${devDependenciesSection()}
${environmentSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when flutter section is out of order', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true)}
${flutterSection(isPlugin: true)}
${environmentSection()}
${dependenciesSection()}
${devDependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when dependencies section is out of order', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true)}
${environmentSection()}
${flutterSection(isPlugin: true)}
${devDependenciesSection()}
${dependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
test('fails when devDependencies section is out of order', () async {
final Directory pluginDirectory = createFakePlugin('plugin', packagesDir);
pluginDirectory.childFile('pubspec.yaml').writeAsStringSync('''
${headerSection('plugin', isPlugin: true)}
${environmentSection()}
${devDependenciesSection()}
${flutterSection(isPlugin: true)}
${dependenciesSection()}
''');
final Future<List<String>> result =
runCapturingPrint(runner, <String>['pubspec-check']);
await expectLater(
result,
throwsA(const TypeMatcher<ToolExit>()),
);
});
});
}