blob: b6e016dccab45d2dcc0310f18b1767fc6f7a4ab4 [file] [log] [blame]
// 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/common/plugin_utils.dart';
import 'package:flutter_plugin_tools/src/readme_check_command.dart';
import 'package:test/test.dart';
import 'mocks.dart';
import 'util.dart';
void main() {
late CommandRunner<void> runner;
late RecordingProcessRunner processRunner;
late FileSystem fileSystem;
late MockPlatform mockPlatform;
late Directory packagesDir;
setUp(() {
fileSystem = MemoryFileSystem();
mockPlatform = MockPlatform();
packagesDir = fileSystem.currentDirectory.childDirectory('packages');
createPackagesDirectory(parentDir: packagesDir.parent);
processRunner = RecordingProcessRunner();
final ReadmeCheckCommand command = ReadmeCheckCommand(
packagesDir,
processRunner: processRunner,
platform: mockPlatform,
);
runner = CommandRunner<void>(
'readme_check_command', 'Test for readme_check_command');
runner.addCommand(command);
});
test('fails when README is missing', () async {
createFakePackage('a_package', packagesDir);
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('Missing README.md'),
]),
);
});
group('plugin OS support', () {
test(
'does not check support table for anything other than app-facing plugin packages',
() async {
const String federatedPluginName = 'a_federated_plugin';
final Directory federatedDir =
packagesDir.childDirectory(federatedPluginName);
final List<Directory> packageDirectories = <Directory>[
// A non-plugin package.
createFakePackage('a_package', packagesDir),
// Non-app-facing parts of a federated plugin.
createFakePlugin(
'${federatedPluginName}_platform_interface', federatedDir),
createFakePlugin('${federatedPluginName}_android', federatedDir),
];
for (final Directory package in packageDirectories) {
package.childFile('README.md').writeAsStringSync('''
A very useful package.
''');
}
final List<String> output = await runCapturingPrint(runner, <String>[
'readme-check',
]);
expect(
output,
containsAll(<Matcher>[
contains('Running for a_package...'),
contains('Running for a_federated_plugin_platform_interface...'),
contains('Running for a_federated_plugin_android...'),
contains('No issues found!'),
]),
);
});
test('fails when non-federated plugin is missing an OS support table',
() async {
final Directory pluginDir = createFakePlugin('a_plugin', packagesDir);
pluginDir.childFile('README.md').writeAsStringSync('''
A very useful plugin.
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('No OS support table found'),
]),
);
});
test(
'fails when app-facing part of a federated plugin is missing an OS support table',
() async {
final Directory pluginDir =
createFakePlugin('a_plugin', packagesDir.childDirectory('a_plugin'));
pluginDir.childFile('README.md').writeAsStringSync('''
A very useful plugin.
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('No OS support table found'),
]),
);
});
test('fails the OS support table is missing the header', () async {
final Directory pluginDir = createFakePlugin('a_plugin', packagesDir);
pluginDir.childFile('README.md').writeAsStringSync('''
A very useful plugin.
| **Support** | SDK 21+ | iOS 10+* | [See `camera_web `][1] |
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('OS support table does not have the expected header format'),
]),
);
});
test('fails if the OS support table is missing a supported OS', () async {
final Directory pluginDir = createFakePlugin(
'a_plugin',
packagesDir,
platformSupport: <String, PlatformDetails>{
platformAndroid: const PlatformDetails(PlatformSupport.inline),
platformIOS: const PlatformDetails(PlatformSupport.inline),
platformWeb: const PlatformDetails(PlatformSupport.inline),
},
);
pluginDir.childFile('README.md').writeAsStringSync('''
A very useful plugin.
| | Android | iOS |
|----------------|---------|----------|
| **Support** | SDK 21+ | iOS 10+* |
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains(' OS support table does not match supported platforms:\n'
' Actual: android, ios, web\n'
' Documented: android, ios'),
contains('Incorrect OS support table'),
]),
);
});
test('fails if the OS support table lists an extra OS', () async {
final Directory pluginDir = createFakePlugin(
'a_plugin',
packagesDir,
platformSupport: <String, PlatformDetails>{
platformAndroid: const PlatformDetails(PlatformSupport.inline),
platformIOS: const PlatformDetails(PlatformSupport.inline),
},
);
pluginDir.childFile('README.md').writeAsStringSync('''
A very useful plugin.
| | Android | iOS | Web |
|----------------|---------|----------|------------------------|
| **Support** | SDK 21+ | iOS 10+* | [See `camera_web `][1] |
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains(' OS support table does not match supported platforms:\n'
' Actual: android, ios\n'
' Documented: android, ios, web'),
contains('Incorrect OS support table'),
]),
);
});
test('fails if the OS support table has unexpected OS formatting',
() async {
final Directory pluginDir = createFakePlugin(
'a_plugin',
packagesDir,
platformSupport: <String, PlatformDetails>{
platformAndroid: const PlatformDetails(PlatformSupport.inline),
platformIOS: const PlatformDetails(PlatformSupport.inline),
platformMacOS: const PlatformDetails(PlatformSupport.inline),
platformWeb: const PlatformDetails(PlatformSupport.inline),
},
);
pluginDir.childFile('README.md').writeAsStringSync('''
A very useful plugin.
| | android | ios | MacOS | web |
|----------------|---------|----------|-------|------------------------|
| **Support** | SDK 21+ | iOS 10+* | 10.11 | [See `camera_web `][1] |
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains(' Incorrect OS capitalization: android, ios, MacOS, web\n'
' Please use standard capitalizations: Android, iOS, macOS, Web\n'),
contains('Incorrect OS support formatting'),
]),
);
});
});
group('code blocks', () {
test('fails on missing info string', () async {
final Directory packageDir = createFakePackage('a_package', packagesDir);
packageDir.childFile('README.md').writeAsStringSync('''
Example:
```
void main() {
// ...
}
```
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('Code block at line 3 is missing a language identifier.'),
contains('Missing language identifier for code block'),
]),
);
});
test('allows unknown info strings', () async {
final Directory packageDir = createFakePackage('a_package', packagesDir);
packageDir.childFile('README.md').writeAsStringSync('''
Example:
```someunknowninfotag
A B C
```
''');
final List<String> output = await runCapturingPrint(runner, <String>[
'readme-check',
]);
expect(
output,
containsAll(<Matcher>[
contains('Running for a_package...'),
contains('No issues found!'),
]),
);
});
test('allows space around info strings', () async {
final Directory packageDir = createFakePackage('a_package', packagesDir);
packageDir.childFile('README.md').writeAsStringSync('''
Example:
``` dart
A B C
```
''');
final List<String> output = await runCapturingPrint(runner, <String>[
'readme-check',
]);
expect(
output,
containsAll(<Matcher>[
contains('Running for a_package...'),
contains('No issues found!'),
]),
);
});
test('passes when excerpt requirement is met', () async {
final Directory packageDir = createFakePackage('a_package', packagesDir);
packageDir.childFile('README.md').writeAsStringSync('''
Example:
<?code-excerpt "main.dart (SomeSection)"?>
```dart
A B C
```
''');
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check', '--require-excerpts']);
expect(
output,
containsAll(<Matcher>[
contains('Running for a_package...'),
contains('No issues found!'),
]),
);
});
test('fails on missing excerpt tag when requested', () async {
final Directory packageDir = createFakePackage('a_package', packagesDir);
packageDir.childFile('README.md').writeAsStringSync('''
Example:
```dart
A B C
```
''');
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['readme-check', '--require-excerpts'],
errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains('Dart code block at line 3 is not managed by code-excerpt.'),
contains('Missing code-excerpt management for code block'),
]),
);
});
});
}